目录
前言:本篇博客主要记录任意文件读取漏洞的靶场实现。
一、任意文件读取漏洞
任意文件读取是属于文件操作漏洞的一种,一般任意文件读取漏洞可以读取配置信息甚至系统重要文件。其中的目录遍历是由于web服务器或者web应用程序对用户输入的文件名称的安全性验证不足而导致的一种安全漏洞,使得攻击者通过利用一些特殊字符就可以绕过服务器的安全限制,访问任意的文件(可以是web根目录以外的文件),甚至执行系统命令。更严重的,导致SSRF漏洞,进而漫游至内网。
可以利用web漏洞扫描器(御剑等)扫描web应用进行检测,也可通过搜索,网站标题包含 “index of” 关键词的网站进行访问,手工探测等。
攻击者通过访问网站某一目录时,该目录没有默认首页文件或没有正确设置默认首页文件,将会把整个目录结构列出来,将网站结构完全暴露给攻击者; 攻击者可能通过浏览目录结构,访问到某些隐秘文件(如PHPINFO文件、服务器探针文件、网站管理员后台访问地址、数据库连接文件等)。简要来说就是老家被偷了。
二、代码实现
2.1 FileRead.vue
前端部分Vue代码如下:
<!--题目名字:FileRead-->
<!--题目类型:任意文件读取-->
<!--题目描述:任意文件读取型漏洞-->
<!--题目难度:4星-->
<template>
<div class="menu">
<el-row>
<!-- 按钮菜单部分 -->
<el-col :span="24">
<el-menu
:default-active="mypath"
class="el-menu-demo"
mode="horizontal"
background-color="#fff"
text-color="#000"
active-text-color="#FF9912"
@select="handleSelect"
>
<el-menu-item index="/honeypot"> </el-menu-item>
<el-menu-item index="/abilitypromotion"></el-menu-item>
<el-menu-item index="/forum" ></el-menu-item>
<el-menu-item index="/navigation" >玄幻</el-menu-item>
<el-menu-item index="/coursemanagement" >都市</el-menu-item>
<el-menu-item index="/usermanagement" >仙侠</el-menu-item>
<el-menu-item index="/usermanagement" >历史</el-menu-item>
<el-menu-item index="/usermanagement" >游戏</el-menu-item>
<el-menu-item index="/usermanagement" >排行</el-menu-item>
</el-menu>
</el-col>
</el-row>
</div>
<div class="building">
<el-card style="width: 60%;margin-left: 20%;margin-top: 2%">
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《三体》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read1" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《明朝那些事儿》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read2" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《我们仨》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read3" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《flag在哪儿》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《解忧杂货店》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read5" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
<el-row>
<el-col :span="3">
</el-col>
<el-col :span="15" style="text-align: left">
<h3>《追风筝的人》</h3>
</el-col>
<el-col :span="6">
<el-button style="" @click="read6" type="warning" plain>详情</el-button>
</el-col>
</el-row>
<el-divider style="background-color: lightgray"/>
</el-card>
</div>
<el-dialog v-model="show" title="书籍详情" width="30%">
<p>{{content}}</p>
</el-dialog>
</template>
<style scoped>
.building{
/*background:url("src/assets/img/bugimg/download.jpg");*/
width:100%;
height:100%;
position:fixed;
background-size:100% 100%;
}
</style>
2.2 FileReadController.java
后端controller类如下:
@RestController
public class FileReadController {
@Autowired
DataSource dataSource;
public String sql;
@RequestMapping("/Read")
public Result fileDownload(@RequestParam("filename") String filename,
@RequestParam("username") String username)
throws IOException {
System.out.println(filename+":ok");
String text;
Result res;
//for flag
//生成flag
String problemid = "pro025";
String flag = null;
String flagMD5 = null;
String flagBase64 = null;
String flagPath = "D://test/flag/"; //引导的文件
String flagPath1 = "/test/flag.txt"; //真正的flag
try {
String sql = "";
Connection connection;
PreparedStatement st;
ResultSet rs;
int row;
connection = dataSource.getConnection();
// 预编译
sql = "select flag from flag where username = ? and problemid = ?";
st = connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
st.setString(1, username);
st.setString(2, problemid);
System.out.println(sql);
rs = st.executeQuery();
// 通过此对象可以得到表的结构,包括,列名,列的个数,列数据类型
rs.last();
row = rs.getRow();
rs.beforeFirst();
System.out.println("查找到行数为"+row);
if(row==1){
rs.next();
flag = rs.getString("flag");
System.out.println("flag已存在:"+ flag);
}
else {
FlagMake flagMake = new FlagMake();
flag = flagMake.getFlag();
System.out.println("生成flag:"+ flag);
//将flag MD5编码后存入数据库
flagMD5 = MD5.getMD5String(flag);
sql = "insert into flag (`username`, `problemid`, `flag`) values ('"+username+
"', '"+problemid+"', '"+flag+"');";
System.out.println(sql);
//PreparedStatement st1 = connection.prepareStatement(sql,ResultSet.TYPE_SCROLL_INSENSITIVE,ResultSet.CONCUR_READ_ONLY);
Statement stmt = connection.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
stmt.executeUpdate(sql);
// st1.executeUpdate();
}
rs.close();
connection.close();
} catch (SQLException e) {
System.out.println("输入内容错误,数据库查询错误 in flag");
System.out.println(e.toString());
//return "输入内容错误,数据库查询错误";
}
saveAsFileWriter(flag,flagPath1);
//读取前端传入的文件内容
text = txt2String(flagPath+filename);
System.out.println(text);
res = new Result(Constants.CODE_200,null,text);
return res;
}
/**
* 读取文件内容
* @param path 想要读取的文件路径
* @return 返回文件内容
*/
public static String txt2String(String path)
throws IOException{
File file;
StringBuilder result;
boolean flag = true;
file = new File(path);/*文件名*/
result = new StringBuilder();
try{
BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
String s = null;
while((s = br.readLine())!=null){//使用readLine方法,一次读一行
result.append(System.lineSeparator()+s);
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
return result.toString();
}
/**
* 写数据到txt文件
* @param filePath 写入文件的路径
* @param content 写入文件的数据
*/
public static void saveAsFileWriter(String content,String filePath)
throws IOException{
FileWriter fwriter = null;
try {
// true表示不覆盖原来的内容,而是加到文件的后面。若要覆盖原来的内容,直接省略这个参数就好
fwriter = new FileWriter(filePath);
fwriter.write(content);
} catch (IOException ex) {
ex.printStackTrace();
} finally {
try {
fwriter.flush();
fwriter.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
三、界面展示
寻找flag的方法在这里就不展示了,只展示题目界面。