pwn入门-4-one_gadget
未完待续: exp有问题…
题目来源:asis ctf quals 2017:start hard
https://github.com/boslash/bo8/tree/master/start_hard
1 | __int64 __fastcall main(int a1, char **a2, char **a3) |
用ida查看反汇编代码,一个很明显的缓冲区溢出漏洞,要看开启了什么保护,没有canary,栈好利用一些,但是开了nx,所以得用rop之类的
1 | [*] '/tmp/starthard/start_hard' |
用one_gadget看有没有
1 | root@VM-24-10-ubuntu:/tmp/starthard# one_gadget ./libc.so.6 |
溢出24字节,然后加上0x4526a即可,但是一直打失败了…是因为libc的问题吧,需要链接上 或者用本地的
0x4526a这个地址行吗???,这个地址是什么地址??
2023 7 28: 感觉思路没啥问题呀… 是不是可以爆破,是加了随机化是吗… 哦对…是libc中的one_gadget呀..那肯定加了随机化…
随机化了三个字符, 所以能怎么输入呢?
1 | from pwn import * |
在之前发送命令就可以!!
把回车重定向进去就可以了把
python3 final.py < huiche > tmp
问题来源:不知道libc的加载基地址
需要解决如何获得libc基址,但是刚才用vmmap查看,然后相加了呀,为啥不行呢?就算可以,对方是远程的,所以这样应该不行…应该需要先打印出来?
不是的,它是因为开了PIE,会有随机化,每次地址都会变
解决办法
libc中的各种函数的相对地址是固定的,按照往常套路,我们需要先泄露出一个函数的地址,然后计算偏移,但是在本题中没法进行泄露(或许可以????)
题解给的办法是,因为我们有read函数,可以利用它和onegadget的偏移,通过爆破?寻找onegadget,直接把read的got表给修改了成onegadget的,然后再次进行调用read就是调用onegadget了,就可以getshell了
所以思路应该是通过栈溢出构造gadget链子,先利用read函数,把read的got表改成onegadget的,然后返回main函数重新执行即可
构造payload
ssize_t read(int fd, void buf, size_t* count**); read函数的含义是,从fd中读取count数据,写入到buf中,
问题是怎么构造read呢? 首先我们知道read的符号地址,可以直接进行调用,然后通过寄存器设置参数, count是不是可以不用设置??
寻找pop rsi的gadget,传入read的got地址到buf变量,然后设置fd为onegadget的地址,然后最后将返回地址设置为main的就可以了!
关于onegadget地址的传参问题
但是问题是题解中的onegadget的地址是直接传参传进来的,不是通过设置rdi,这是为啥呢???
是因为此时rdi为0,所以从标准输入中获取嘛?我觉得应该是,并且这个让我想到了pwnable的第一题…那应该就不奇怪了
关于onegadget 用的libc的问题
用的如果是自己的libc的话,
readelf -s /lib/x86_64-linux-gnu/libc.so.6 | grep read@
ROPgadget –binary /lib/x86_64-linux-gnu/libc.so.6 –only ‘pop|ret’
0x000000000002164d : pop rsi ; pop r15 ; ret
echo 0 > /proc/sys/kernel/randomize_va_space
最终exp
这是作者给的原exp,实际上用的话可能需要简单修改
该exp首先填满缓冲区,然后通过 pop_rsi把read的got表地址赋值给rsi,即后面read的第二个参数buf,也就是我们要覆盖的地址,后面8个A是因为用的gadget多了一个pop r15,填入个垃圾数据就可以了. 然后pop完之后继续往下执行,执行到read的symbols,也就是去执行read函数,此时read还没有第一个参数fd,也就是从哪里读取,但是在调试的时候发现rdi是0,也就是从标准输入读取.不过为什么那么巧,rdi是0呢???万一不是0呢? 如果不是0的话,就需要gadget进行布置了
1 | from pwn import * |
其他需要储备的知识 + 问题
64位传参
和32位 不同的是,要用到寄存器: rdi rsi rdx rcx
关于read函数
https://man7.org/linux/man-pages/man2/read.2.html
关于下断点调试分析
可以在call _read指令后面下断点,然后一点点调试分析
一直以来都犯了一个错误,觉得下断点应该在exp中用pause(),但是一直不知道怎么在payload打出去后,断下来,应该及时和同学交流的,这个问题的答案其实自己早就知道了,只是不知道原来是这样…
gdb.attach(io,”b __libc_start_main”) 其实就是这句, gdb attach的话下个断点就可以了,这样就可以在payload打之后一点点调试了
https://blog.csdn.net/fjh1997/article/details/105434992/
pop rsi是把它下面的那个给pop出来?还是找rsp?
看下面的第六行,这里pop rsi的话,是放在了返回地址,所以当执行到这里的时候,上面的栈的数据就是垃圾数据了,此时pop rsi下面这里是rsp的位置???
1 | gef➤ telescope |
给的libc.so.6怎么链接?
/libc.so-3.6
GNU C Library (Ubuntu GLIBC 2.23-0ubuntu7) stable release version 2.23, by Roland McGrath et al.
Copyright (C) 2016 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
参考
https://devcraft.io/posts/2017/04/09/start-hard-asis-ctf-quals-2017.html