一、Web

old

image.png
任意文件读取,不过flag.txt 读不了,但可以看 hint.txtsmali 字节码,提示了 fastjson 1.2.24
image.png
先读取本进程相关目录
image.png
/usr/local/run/start.jar 获取源码,IDEA打开分析
image.png
原来过滤了 flag ,怪不得读取不了

往反序列化方向,不过有waf
image.png

然后还有限制
image.png

这里卡了挺久,试了网上很多EXP,都不行
然后突然想起fastjson反序列化的原理
一般是需要别的库的配合,通过反射获取相关方法的
于是我一个个依赖找
image.png
搜了下 spring ,没有相关漏洞,但是在 tomcat dbcp 里刚好发现了可以利用,而且不用利用 rmi ldap 之类的
https://kingx.me/Exploit-FastJson-Without-Reverse-Connect.html
然后刚好用到 BCEL,HFCTF2021也刚好用到, 刚好复现过了,所以非常熟练 (
https://github.com/f1tz/BCELCodeman
编写 java poc,转换为 class 然后生成 BCEL

这样可以绕过waf的黑名单,即绕过了第1个challenge
还有2个 challenge,这个简单,就长度大于2000,然后需要包含 flag 关键字

这里直接把 /flag.txt改一下名读取即可
image.png
image.png

try_js

审计源码
image.png
你要merge,那我可就不困了,明显的原型连污染

污染一下原型
image.png
即可成功登录
image.png

接下来,就没有然后了,,
image.png
除了输入黑名单以外的东西,都是直接断开连接,晕
image.png
emm 快结束了,,环境就可以了????
image.png

fuzz
image.png

.DS_Storemac的备份文件,有的小伙伴应该遇到过,就解压了mac的压缩包,莫名其妙多了这个文件

通过 shellme.php 得知 flag/var/www/flag

然后通过 y0u_w1ll_s3e_Me.txt 知道源码

  1. <?php
  2. classname = "SayHi";
  3. $this->param = array("C", "T", "F", "E", "R");
  4. $tmp = new $this->classname($this->param); }
  5. public function __destruct()
  6. { if (strpos($this->param, 'flag') !== false || strpos($this->param, '?') !== false || strpos($this->param, '*') !== false)
  7. { die('You want to hack me?'); }
  8. else
  9. { $text = new $this->classname($this->param); foreach ($text as $t) { echo ($t); } }
  10. }
  11. public function __wakeup()
  12. {
  13. $this->checkMethod = new Check;
  14. if ($this->checkMethod->vaild($this->param) && $this->checkMethod->vaild($this->class))
  15. { echo ("You are a good man!"); }
  16. else
  17. { die('You are a hacker?'); }
  18. } }
  19. class SayHi {
  20. public $a;
  21. public function __construct($a)
  22. { $this->a = $a; array_push($this->a, "HELLO"); return $this->a; }
  23. }
  24. class Check
  25. {
  26. public function vaild($code)
  27. {
  28. $pattern = '/[flag|file|!|@|#|$|%|^|&|*|=|\'|"|:|;|?]/i';
  29. if (preg_match($pattern, $code))
  30. { return false; }
  31. else { return true; }
  32. } }
  33. if (isset($_GET['p'])) {
  34. unserialize($_GET['p']);
  35. } else {
  36. $v = new Verify;
  37. }

也就是 y0u_w1ll_s3e_Me.php 的源码

就反序列化,,一下,,就可以了,但时间不够了,,晕

二、MISC

比赛结束了,题目名字没有记。。

0x01

下载下来是一个test.pcapng,看到后缀习惯性打开Wireshark看看,啥也没看出来
strings看到hint
image.png
提示说要binwalk,行吧
image.png
唔。。有个rar,上foremost
image.png
打开压缩包,里面有个flag.txt
image.png
MZWGCZ33MZUW4ZC7OJSWC3C7O5QXSX3UNBQW4X3ZN52V6Y3BNZPXO2LOPU======
hint说是base16,解码失败。我直呼好家伙!
base32
flag{find_real_way_than_you_can_win}

这题,以为是流量分析题,其实不是。。。hint说base16,其实不是。。。
*点赞!

0x02

文件下载下来叫做pig.png,???这不是gif嘛
binwalk看看有啥东西
image.png
有个zip,上foremost
image.png
压缩包要密码。先让暴力破解跑一下

接着拉出Stegsolve看看,有个二维码
那明显了,一共25帧动画,一帧就有一部分二维码呗
image.png

一帧保存一次图片,然后拉进Photoshop
25个图层,这拼图真好玩哈哈呜呜呜呜呜。。。image.png
扫出来这玩意
JUZFU2C2NJTTETKUKF3Q====
base32解码:M2ZhZjg2MTQw
接着继续
base64解码:3faf86140

压缩包密码出来了,3faf86140
image.png
猪圈密码,解密得flag{this_isa_pigpen_fake_flag}
凸(艹皿艹 ),这题贼浪费时间,主要就是那个拼图呜呜

三、CRYPTO

rsa

直接打开rsa.py
先看开头

assert hashlib.new('md5', text).hexdigest() == flag[5:-1]
text = m1 + m2 + m3

flag是text的MD5,text由m1,m2,m3拼接得到,破解这三段明文即可获取flag

首先是m1的部分

p1 = getPrime(512)
q1 = getPrime(512)
n1 = p1 * q1
phi = (p1-1) * (q1-1)
while True:
    d1 = getRandomNBitInteger(200)
    if GCD(d1, phi) == 1:
        e1 = inverse(d1, phi)
        break
m1 = bytes_to_long(m1)
c1 = pow(m1, e1, n1)
print (c1,e1,n1)

注意到输出文件中e1与n1差不多大,相比起来d1就小多了,因此考虑低解密指数攻击
运用工具rsa-wiener-attack

#!/usr/bin/python
#coding:utf-8

import hashlib
from Crypto.Util.number import *
import RSAwienerHacker
c = 51084654001062999676284508744761337160593155669881973332922269056143420517629679695048487021241292007953887627491190341353167847566083172502480747704275374070492531393399916651443961186981687573379323436438906676133035045064486529453649419053918833072924346775468502743027859482041178726542991466613589539914
n = 151092363916177851152025151918241584641682210212036254637668925062407387596818893923128056380386244596150134405578253100187360613990057596729265767426618262474915825169178445560157476701330766996735046666440633251722785157310664928275249725806466188778983132016426476941426227570021630850606892034122220619913
e = 8336175595129952911533542789423826996569722546516271636161500363234194699197831564741315089461869306051343021000467004786843886241187253481694116720349730349091091395871354352082596957433423648367398183367388782648648524548000549086553610297047964333156830786192545363469852460230159194760278103213655609189
d = RSAwienerHacker.hack_RSA(e,n)
print(d)
m=pow(c,d,n)
m=long_to_bytes(m)
print(m)

m1为“So long as men can breathe or eyes can see, So long lives this and this gives life to thee.”

接下来是m2的部分

m2 = bytes_to_long(m2)
n2 = 0x57696c78e1d443a3c9211963c721c16e47068eb3b52dfb79ef55af340e7894c7e301a5f38734ddd10e67d0dd2f5759ae0443ca47719d82bfcccc9d26b05043b0b66b253219f266ea133fc613e23dbe14d5f731c5ad4158286a1139e2927b8a485df0e662d77277f61f4ff334a24b51959e399e5e778b6934897b6b9f4b315207L
n3 = 0xc7e5c4318b4376a93588ea853a70f5576aaa3a291acff806f87b00b01443edfd9298915343e8d219fc09ab464c02d12fa72abb0e70d40b12c63274bcf4a61ccb7c81d42fbb04f54e9ce972c3467c851932ecf8f0ada57f56ee91dad3837669fc501d69c68dce305d62cd1f09acff28874792ef343fca185bdc9d2432fd45d3d1L
n4 = 0x8d0899da21f7a50a5a869b0914fdfbc7d67aa85941021403889d24cb5b8029dd45a14e02f83dba7c21b3759fb152e045dcad6f11421e578a1b01d5e0b077810fc33e5f8d6d8e3623d278c908bbf7f4f7adb7224014e1f14272214e1a05cf4314dd950290fddbec9870be2c1d100bcdaf7056a1b909a400bb1f549efbede68bcfL
c2 = pow(m2, e2, n2)
c3 = pow(m2, e3, n3)
c4 = pow(m2, e4, n4)
print (c2,c3,c4)

使用了三个不同的模数对m2加密,加密指数未知
这里先猜想三个加密指数相同且不大,尝试一波低加密指数广播攻击

#!/usr/bin/python
#coding:utf-8

import gmpy2
from Crypto.Util.number import long_to_bytes

def CRT(items):
    N = reduce(lambda x, y: x * y, (i[1] for i in items))
    result = 0
    for a, n in items:
        m = N / n
        d, r, s = gmpy2.gcdext(n, m)
        if d != 1: raise Exception("Input not pairwise co-prime")
        result += a * s * m
    return result % N, N

for e in range(1,100):
    print "e="+ str(e)
    n = [61382661432613438326655148450768087076260128857721147439556800536654539027087846029229588571299942048385386053047326563339872519993620168053109706810552163690742849532083123203140399507121351975949699755447361539636998671413789819616908205465110034319443100288084230570762354691041724667597820223114362049031,140372815716763724976054669022743457910392959043904693888351103887272413865633125292544322731597391017979681119966053697292718088814246548058655102742481335196832403429006064211456812081357779298369772470111182338928284934545092906761948215213617982316149425733392948482775042013684870116402263939033191535569,99037160228151783989907356340642882605745788564918144439395364395269547788397774374655030273447185200759418139502369653888918486999493785062322031098498901981474578492235967396611683594622447512647938941366988036248788552107704499720131834973828854567748413952704412163124927094433848903433723343988003867599]
    c = [24168576475826731342981309869386844888048819155804916609868467364828794195081900378454942799582364951590154660883127133517306279315632213654294241046389472660162658285116025022019193389467425762033793233310853287285710051131156746537960416278314488047201950871542871471614834606092674080171837479678908485762,59042322068112449729750363498227925481549151238455994334741763136215058751527859574931116063334209500284095818008451340013716449554106507373112252757273078880364298445003064190906862585372984554264625861222115429779924444369582923270264732188891567089849725691839301479707767233813043465943547876632578498984,86124343357786577132154304914637897169467679024253471444678880447274558440276584635040507167438356800005540641456548793163113750596432451742228432593182300337042281015596655874375158300461112977200671847176880860698060672936210257455599090524023845268651175379694950602443080246153556268191330489901634436]
    data = zip(c, n)
    x, n = CRT(data)
    m = gmpy2.iroot(gmpy2.mpz(x), e)[0].digits()
    print long_to_bytes(m)

注意到e=3处输出了一段有意义的文本
m2为“Chest has a bright ambition, no high can not be climbed.”

最后是m3的部分

m3 = bytes_to_long(m3)
p5 = getPrime(1024)
q5 = getPrime(1024)
n5 = p5 * q5
print pow(m3,e5,n5)
print (e5,n5)
print p5>>428

这里比较特别的是给出了p的高位
尝试分解n求出p和q
在Sage Cell Server运行以下SageMath脚本

n = 12382768780688845948585828171746451695620690637388724603203719934675129634162669400211587652801497553140445052212955447547285342951827548927777971592012005336108991182804517438932388430909818349339928033362693776498198280566445301283769762658236093273135470594245556180103947875110497679850836950853434075025187940546602828416710260312146348085635062790163306288554171471977697811571151068804586709977754482736587083043633360827556846476139372134496068081264161278183780518986923815627524813237434789592133132430580528353375704616450593022343415392743694469637309237497448893478902243349283615118435345397909237495251
p_fake = 182635381484380563458311202271781328898053732908212705893542973352083240894286209775590202544476913342359034598901737742898345569752615514577169505593025259879429231797401548503324<<428
pbits = 1024
kbits = 428
pbar = p_fake & (2^pbits-2^kbits)
PR.<x> = PolynomialRing(Zmod(n))
f = x + pbar
x0 = f.small_roots(X=2^kbits, beta=0.4)[0]
print(int(x0 + pbar))

输出结果即为p
知道了p就能够计算出私钥d,进一步还原明文

#!/usr/bin/python
#coding:utf-8

from Crypto.Util.number import *

c = 7479226689503128706443123521570581658668839203982072419275773066090139369387752424856982287500754805036668221578674582111373214400048065981143586768159093517856729586240876781314226713473457848588205839635234624256432258024026698381646902196832849461804350553542541128509121012667792037004716033974053614737451942287543723238730054875983726091182977666880984732837604625557483621161056089767140997756267432137190239967241490004246596723655769407636914860893150081043179313259622038983431488143887092338693868571374510729082940832360819295528352729394196810748661957966996263811903630229686768254608968394381708296458
e = 65537
n = 12382768780688845948585828171746451695620690637388724603203719934675129634162669400211587652801497553140445052212955447547285342951827548927777971592012005336108991182804517438932388430909818349339928033362693776498198280566445301283769762658236093273135470594245556180103947875110497679850836950853434075025187940546602828416710260312146348085635062790163306288554171471977697811571151068804586709977754482736587083043633360827556846476139372134496068081264161278183780518986923815627524813237434789592133132430580528353375704616450593022343415392743694469637309237497448893478902243349283615118435345397909237495251
p = 126596896828983947657897211653294325357694173315986362964483543178327683872006349352506228192861938882562062524573153829867465009733178457399135420215887364009777012624212242069216745138202953735034716032666189414323613790242613717531697843979604409625853777348356827810939640137432278820298916431800157020739
q = n // p
phi = (p-1) * (q-1)
d = inverse(e,phi)
m = pow(c,d,n)
print long_to_bytes(m)

m3为“You never know how strong you really are until being strong is the only choice you have.”

拼接m1,m2,m3并计算MD5值
得到flag{096d9ddd8c911b95d91fa7d6d7460c3c}
这题一大半时间在搭环境,114514个报错,哼啊啊啊啊啊啊啊

四、RESERVE

Easy_re

直接扔进IDA里看看情况
QQ图片20210523231013.png
嗯?“这个男人必须die”这串东西也太扎眼了
忍不住问问搜索引擎
搜索引擎不负众望,找到了一篇writeup——https://www.d0g3.cn/2018syb-wp.html#toc-18
参考这篇writeup的解法,程序需要的a short name应该是“Hanzo”
53.png
10523231959.png
根据IDA的结果可得flag是输入的MD5
得到flag{3682d76cec61a12ffea928ce0521e780}
搜索引擎yyds
什么叫非预期解啊(战术后仰