L3HCTF部分web题复现

best-profile 先看代码,问题在这部分 @app.route("/ip_detail/<string:username>", methods=["GET"]) def route_ip_detail(username): res = requests.get(f"http://127.0.0.1/get_last_ip/{username}") if res.status_code != 200: return "Get last ip failed." last_ip = res.text try: ip = re.findall(r"\d+\.\d+\.\d+\.\d+", last_ip) country = geoip2_reader.country(ip) except (ValueError, TypeError): country = "Unknown" template = f""" <h1>IP Detail</h1> <div>{last_ip}</div> <p>Country:{country}</p> """ return render_template_string(template) 经典的ssti模板注入,在比赛的时候一直尝试 甚至都怀疑到了是否能绕过string:username,走目录遍历,结果是nginx的缓存投毒,在做题的时候我甚至都没去注意这个文件 location ~ .*\.(js|css)?$ { proxy_ignore_headers Cache-Control Expires Vary Set-Cookie; proxy_pass http://127.0.0.1:5000; proxy_cache static; proxy_cache_valid 200 302 12h; } 特殊后缀proxy_cache static开启了缓存,因为用户注册时并没有限制特殊字符,则我们可以通过构建类似与test.js 的用户名来访问/get_last_ip/ 欺骗缓存,这样服务器通过 requests.get 访问即使没有cookie也会返回缓存数据 构建用户 ...

July 15, 2025 · 3 min · 448 words · neko

巅峰极客复现

复现会 php_online can you break this sandbox? 给了py文件,先读代码 第一眼过去肯定是看到/路由下的id传参,即 session['id'] = id # 将ID存储在会话中。 if not os.path.exists(f'/sandbox/{id}'): # 检查沙箱目录是否存在,如果不存在,则创建。 os.popen(f'mkdir /sandbox/{id} && chown www-data /sandbox/{id} && chmod a+w /sandbox/{id}').read() 这块内容,在复现会中师傅也说过题目在这里卡住了,想法是这个id的位置是否能够伪造,但是想到其在 if not id.isalnum() or len(id) != 8:这里就做了判断,其实是不行的,个人觉得这应该就是一个陷阱,继续往后跟踪,在创建沙箱后路由重定向到了/sandbox 在这里,code是可控的 code = request.form.get('code') 继续往下,第一个os操作会先进入到以用户id为名的文件夹中,并清空文件,而后以www-data的权限cp将app文件夹下的init.py复制到当前用户的目录,并以www-data的权限执行 os.popen(f'cd /sandbox/{user_id} && rm *').read() # 清空用户ID对应的文件夹 os.popen(f'sudo -u www-data cp /app/init.py /sandbox/{user_id}/init.py && cd /sandbox/{user_id} && sudo -u www-data python3 init.py').read() 然后删除之前的php代码,创建新的phpcode文件,写入code传入的参数 php_file = open(f'/sandbox/{user_id}/phpcode', 'w') # 打开PHP代码文件 php_file.write(code) # 将提交的代码写入文件 php_file.close() # 关闭文件 之后以nobody的权限执行php代码,完成后删除文件 ...

September 23, 2024 · 2 min · 382 words · neko

2024 长城杯复盘

2024 长城杯 这次比赛输出感人,属于是一个人拖了后退,但也并非都没好的,起码知道缺哪快营养了 misc 漏洞寻踪,流量解密 需要拿到流量包中的攻击者作为二阶段的密码,但是当时试过了所有对服务器发动攻击的ip都没用,遂一怒之下搓了个脚本遍历出整个网段作为密码进行爆破 import ipaddress def ips(network): net = ipaddress.ip_network(network, strict=False) with open('ips.txt', 'w') as file: for ip in net.hosts(): file.write(str(ip) + '\n') ips('192.168.30.0/24') 力大砖飞 后续查找的时候只在log文件中找到了这个ip,没有在cap找到,也还好没有死磕 第二阶段,黑客通过漏洞点往服务器发送命令,下载了两个文件 http.request.uri == "/ispirit/interface/gateway.php" 过滤.1.5 ip.addr == 192.168.1.5 (事后诸葛亮:我寻思这是个伏笔) 这样就拿到了key和raw key:bdb8e21eace81d5fd21ca445ccb35071 raw:bdb8e21eace81d5fd21ca445ccb350715a76f6751576dbe1af49328aa1d2d2bea16ef62afa3a7c616dbdb8e21eace81d5fd21ca445ccb35071 理论上 通过观察可以看到raw的内容有两个部分是和key相同的即bdb8e21eace81d5fd21ca445ccb35071 5a76f6751576dbe1af49328aa1d2d2bea16ef62afa3a7c616d bdb8e21eace81d5fd21ca445ccb35071,但好似不死我就是没发现,上面的流量包其实也在暗示。。 题解 web sqlup 登陆页 看到sql第一反应是sql注入,就拿着yakit和sqlmap在跑,但越跑越不对劲,一点报错都没有,然后就想到了爆破,用yakit跑了一个字典得到了 u p s a e s r s : w a d d : m 0 i n 进去后,头像位置有个文件上传,但是过滤字符p,当我还在寻思怎么绕过的时候队友已连上shell了。。。 ...

September 9, 2024 · 1 min · 71 words · neko

2024闽盾复现

闽盾杯 复现 部分 logo隐写 zstag使用,很惭愧之前完全没接触过此类工具 excel隐写 execl表格,考的是vba宏的使用 点击查看宏 可以看到一个加密和一个解密,点击解密 就可以看到flag,但很明显是乱的,经过测试对计算机分数进行降序排列即可拿到正确的flag flag{jisuanjichengjijuedingbisaipaiming} 变个样就不认识我了? 也是个图片隐写,使用zsteg读取可以看到类似base64的信息 他的意思应该是存在冗余数据,那就不用他了,直接010查看 猜测上方应该是base表下方应该是编码后的数据,使用万能解码试试 W9i4WoeEJAy7Un/hV8u/WT870Tq2J6xjKEl= 不行,根据提示是base表出现了问题,base标准表结构应该是ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= A-Za-z0-9+/= 我们拿到的内容是xyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/所以可以大胆猜测其内容为他为正常base表字母字符的颠倒结构即abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/= 卡住了 问过大佬后得知,并非补全而是跟在后面 xyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/abcdefghijklmnopqrstuvw 我不是二维码 拿到信息,随波逐流梭哈 这题的使用的是AES加密,在做题的时候一直以为的base64的换表,密钥和偏移都为文件名42nudiehheidun24 出题人的上网流量 拿到这道题目的时候第一反应的http,webshell的流量分析做多了有点路径依赖了,这不该,再看看可以看到一些smtp 过滤smtp 很明显的qqmali流量 追踪tcp流 导出为eml后缀文件后用能解析邮件格式的软件打开即可看到doc文件 另存为附件,发现密码,根据提示接收人是吴的qq在闽盾qq群查找 获得密码 217778

June 23, 2024 · 1 min · 34 words · neko

R3PHP wp

R3PHP 如果没有题解我绝对想不到 原题: <?php error_reporting(0); if(strpos($_REQUEST['url'],"http")===0){ $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>$_REQUEST['header']) ); $context = stream_context_create($opts); $file = file_get_contents($_REQUEST['url'], false, $context); // echo $file; # no show for u }else{ echo "hacker!"; } highlight_file(__FILE__); ?> 应该是出题人的人说 First, by reading the code, you can know that it is a blind ssrf, and then you can also pass the header header After casually entering a url, I found that 404 is phpstudy, and I can tell that it is a small skin panel of linux. The code of phpstudy Panel, audit found that all requests go through port 8090: ...

June 11, 2024 · 3 min · 602 words · neko

LIT CTF2024复现

好像有好多题目还没上传,现写上传了的 exx 经典带回显xxe漏洞 照抄payload: <?xml version="1.0"?> <!DOCTYPE as [ <!ENTITY f SYSTEM "file:///flag">]> <user><username>admin&f;</username><password></password></user> 值得注意的是,需要带file伪协议否则带不出来 百万美元的诱惑 源代码 <?php error_reporting(0); $a = $_GET['a']; $b = $_GET['b']; $c = $_GET['c']; if ($a !== $b && md5($a) == md5($b)) { if (!is_numeric($c) && $c > 2024) { echo "好康的"; } else { die("干巴爹干巴爹先辈~"); } } else { die("开胃小菜))"); } 重点是: if ($a !== $b && md5($a) == md5($b)) { if (!is_numeric($c) && $c > 2024) { 第一段做了一个判断,很明显需要做md5碰撞ab传参分别是a=QNKCDZO&b=240610708,第二个使用了is_numeric()函数判断不是数字的同时需要他大于2024,查了一下可以借url编码中的空字符绕过 最后得到 ?a=QNKCDZO&b=240610708&c=2025%20 得到一个文件名字./dollar.php,访问是下一模块 <?php //flag in 12.php error_reporting(0); if(isset($_GET['x'])){ $x = $_GET['x']; if(!preg_match("/[a-z0-9;`|#'\"%&\x09\x0a><.,?*\-=\\[\]]/i", $x)){ system("cat ".$x.".php"); } }else{ highlight_file(__FILE__); } ?> 看的出来通过preg_match过滤的大部分的字符,在网上查了一圈发现了一个神奇的方法,利用$()这三个字符就可以组成,逻辑大致如下 ...

June 7, 2024 · 2 min · 233 words · neko