WebGoat 8.0 M21失传几关的答案在这里

2023-12-20 14:20

本文主要是介绍WebGoat 8.0 M21失传几关的答案在这里,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这篇文章是去年我发在freebuf上的,忘了…这两天上freebuf才发现没有收录到博客里,收录一下吧,反正都是自己的东西。。。
原文:https://www.freebuf.com/vuls/177923.html

最近在研究OWASP WebGoat8.0,鲜鲜实验室有一篇文章特别好,从安装到攻略都有(传送)。但其中有几关这位大佬没有做出答案(但我做出来了),当然我在网上找了一些攻略也没有这几关的具体答案,所以把自己做的答案贴出来,给也在研究这个靶场的兄弟们作参考。

最后挑战WithoutAccount

这道题就是最后一关,页面的意思是投票,点击星星来决定投几星。

1.png

1.png

有意思的是,当我们点击星星之后提示我们需要登录才能投票,但这个页面并没有登录按钮。

我们来查看后台源码:

@GetMapping(value ="/vote/{stars}", produces = MediaType.APPLICATION_JSON_VALUE)

   @ResponseBody

   public ResponseEntity<?> vote(@PathVariable(value ="stars") int nrOfStars, HttpServletRequest request) {

       //Simple implementation of VERB Based Authentication

       String msg = "";

       if (request.getMethod().equals("GET")) {

           HashMap<String, Object> json = Maps.newHashMap();

           json.put("error", true);

           json.put("message", "Sorry but you need to login first inorder to vote");

           return ResponseEntity.status(200).body(json);

       }

       Integer allVotesForStar = votes.getOrDefault(nrOfStars, 0);

       votes.put(nrOfStars, allVotesForStar + 1);

       return ResponseEntity.ok().header("X-Flag", "Thanks forvoting, your flag is: " + Flag.FLAGS.get(8)).build();

}

查看了源码后发现,只要是GET请求都会返回失败。但这个GetMapping就是get提交的,所以我的思路是,使用其他方法提交请求绕过,先将GET改为POST提交。

2.png

2.png

失败了。

然后换成PUT,还是失败,之后换成HEAD,发现了flag。(就是这么简单)

3.png所以这道题主要还是考对http协议的熟悉,假如就只知道提交方式GET,POST,PUT是做不出来的。

3.png所以这道题主要还是考对http协议的熟悉,假如就只知道提交方式GET,POST,PUT是做不出来的。

SQL Injection(mitigation)

这道题的意思是我们可以对下面四个主机排序,可以根据hostname,ip,mac,status,description等,对应的山下箭头就可以排序,但需要注意的是,下面的提交框不存在注入(题目也说明了)。最后我们要找到主机“webgoat-prd”的ip地址。

4.png

4.png

没什么好说的,直接抓包查看数据提交方式:
5.png

5.png

发现是get提交,对排序的参数直接写在后面了。我们放入repeater进行重放,查看相应包:
6.png

6.png

右侧就是排序的数据,目前已经按ip排序好了,我们可以尝试修改参数查看是否能排序:
7.png

7.png

可见已经按照id改好了,但id选项并没有在网页上。我们再根据提示简单构造一个逻辑语句:
8.png

8.png

可见已经按照ip排序了,我们将true换成false试试:
9.png

9.png

变成了根据ip排序,所以我们可以将true和false的位置换成逻辑语句,此处存在order by布尔盲注。WebGoat用的是HSQLDB,这个数据库貌似并没有类似mysql的information_schema库,所以表名只能暴力破解,使用逻辑语句:

exists(select * from table_name)

table_name就是需要暴力破解的地方。这道题的表是servers,相比不算难破解。(至少使用字典使用牛津的那本就可以,手动滑稽)

接下来直接构造逻辑语句就好

/WebGoat/SqlInjection/servers?column=(CASE+WHEN+((select+left(ip,1)+from+servers+where+hostname='webgoat-prd')='1')+THEN+id+ELSE+description+END)

算是传统的布尔注入payload,但注意的是left要放在ip前面,而不是整个select语句前面。最后拆解出的答案是104.130.219.202

SQL Injection(advanced)

这关也是最后challenge的第三关,是让我们使用tom的账户登录。但除了用户名是tom意外什么也不知道。但给了我们一个注册页面。首先查看后台的语句,登录部分:

 private static final String PASSWORD_TOM = "thisisasecretfortomonly";

    //Make it more random at runtime (good luck guessing)

    private static final String USERS_TABLE_NAME = "challenge_users_6" + RandomStringUtils.randomAlphabetic(16);

    @Autowired

    private WebSession webSession;

    public SqlInjectionChallenge() {

        log.info("Challenge 6 tablename is: {}", USERS_TABLE_NAME);

    }

源码中直接写出了tom的密码,可以直接提交成功过关。但如果想sql注入出密码的话需要费些功夫。

 @PutMapping  //assignment path is bounded to class so we use different http method :-)

    @ResponseBody

    public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception {

        AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);

        if (attackResult == null) {

            Connection connection = DatabaseUtilities.getConnection(webSession);

            checkDatabase(connection);

            String checkUserQuery = "select userid from " + USERS_TABLE_NAME + " where userid = '" + username_reg + "'";

            Statement statement = connection.createStatement();

            ResultSet resultSet = statement.executeQuery(checkUserQuery);

            if (resultSet.next()) {

                attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build();

            } else {

                PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " + USERS_TABLE_NAME + " VALUES (?, ?, ?)");

                preparedStatement.setString(1, username_reg);

                preparedStatement.setString(2, email_reg);

                preparedStatement.setString(3, password_reg);

                preparedStatement.execute();

                attackResult = success().feedback("user.created").feedbackArgs(username_reg).build();

            }

        }

        return attackResult;

    }

:-)

    @ResponseBody

    public AttackResult registerNewUser(@RequestParam String username_reg, @RequestParam String email_reg, @RequestParam String password_reg) throws Exception {

        AttackResult attackResult = checkArguments(username_reg, email_reg, password_reg);

        if (attackResult == null) {

            Connection connection = DatabaseUtilities.getConnection(webSession);

            checkDatabase(connection);

            String checkUserQuery = "select userid from " + USERS_TABLE_NAME + " where userid = '" + username_reg + "'";

            Statement statement = connection.createStatement();

            ResultSet resultSet = statement.executeQuery(checkUserQuery);

            if (resultSet.next()) {

                attackResult = failed().feedback("user.exists").feedbackArgs(username_reg).build();

            } else {

                PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO " + USERS_TABLE_NAME + " VALUES (?, ?, ?)");

                preparedStatement.setString(1, username_reg);

                preparedStatement.setString(2, email_reg);

                preparedStatement.setString(3, password_reg);

                preparedStatement.execute();

                attackResult = success().feedback("user.created").feedbackArgs(username_reg).build();

            }

        }

        return attackResult;

    }

 @RequestMapping(method = POST)

    @ResponseBody

    public AttackResult login(@RequestParam String username_login, @RequestParam String password_login) throws Exception {

        Connection connection = DatabaseUtilities.getConnection(webSession);

        checkDatabase(connection);

        PreparedStatement statement = connection.prepareStatement("select password from " + USERS_TABLE_NAME + " where userid = ? and password = ?");

        statement.setString(1, username_login);

        statement.setString(2, password_login);

        ResultSet resultSet = statement.executeQuery();

        if (resultSet.next() && "tom".equals(username_login)) {

            return success().build();

        } else {

            return failed().feedback("NoResultsMatched").build();

        }

    }

可以看见,登录过程和注册信息入库过程都启用了预编译,几乎没有什么注入可能,唯一有注入点的地方就是检查用户是否注册过这里,直接把username_reg拼接在sql语句中,我的用户名是breeze,再次注册会提示我已经注册过,但我如果把用户名改为breeze’ and1=2 –就会提示我创建账户成功。这样我们就可以在and后构造逻辑语句来进行布尔注入了。但问题是,如何知道表名。
10.png

10.png

在源码中,我们看出,这张表每次使用都会创建新的,用完删除,而表名是challenge_users_6加上随机生成的16位长度的字符串,几乎不可能暴力破解了。但它讲表名输出到了服务器的log上,所以我们可以去log查看本次的表名
11.png

11.png

这次的表名是challenge_users_6WDzKXNcjaYiNPkSr,根据这个表名构造逻辑语句,前面的用户我们使用没有注册过的breeze123,那么查询结果就是假,后面使用or+逻辑语句,这样我们的逻辑语句是真就会返回假,是假就会返回真。

逻辑语句:

breeze123'+or+(select+left(password,1)+from+challenge_users_6WDzKXNcjaYiNPkSr+where+userid='tom')='a'+--

12.png13.png写一个脚本就可以得到密码 thisisasecretfortomonly了

12.png 13.png写一个脚本就可以得到密码 thisisasecretfortomonly了

参考:鲜鲜实验室-“Web安全攻防靶场之WebGoat”-http://www.xianxianlabs.com/2018/06/03/webgoat1/

*本文作者:BreezeC,转载请注明来自FreeBuf.COM

这篇关于WebGoat 8.0 M21失传几关的答案在这里的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/516358

相关文章

poj 3104 二分答案

题意: n件湿度为num的衣服,每秒钟自己可以蒸发掉1个湿度。 然而如果使用了暖炉,每秒可以烧掉k个湿度,但不计算蒸发了。 现在问这么多的衣服,怎么烧事件最短。 解析: 二分答案咯。 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <c

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

【附答案】C/C++ 最常见50道面试题

文章目录 面试题 1:深入探讨变量的声明与定义的区别面试题 2:编写比较“零值”的`if`语句面试题 3:深入理解`sizeof`与`strlen`的差异面试题 4:解析C与C++中`static`关键字的不同用途面试题 5:比较C语言的`malloc`与C++的`new`面试题 6:实现一个“标准”的`MIN`宏面试题 7:指针是否可以是`volatile`面试题 8:探讨`a`和`&a`

Linux 删除 当前下的 mysql-8.0.31 空文件夹

在Linux中,如果你想要删除当前目录下的名为mysql-8.0.31的空文件夹(即该文件夹内没有任何文件或子文件夹),你可以使用rmdir命令。但是,如果mysql-8.0.31文件夹并非完全为空(即它包含文件或子文件夹),rmdir命令会失败。 如果你的目标是删除mysql-8.0.31文件夹及其内部的所有内容(无论是否为空),你应该使用rm命令结合-r(或-R,它们是等价的)选项来递归地删

mysql数据库8.0小版本原地升级

mysql数据库8.0小版本原地升级 准备工作升级工作停库使用新版本软件启动数据库更新环境变量重启数据库 升级日志 OS release: CentOS 7.9升级前DB version: MySQL 8.0.30数据库升级安装包:mysql-8.0.36-linux-glibc2.12-x86_64.tar.xzMySQL Shell安装包:mysql-shell-8.0.36

上海大学《2022年836+915自动控制原理真题及答案》 (完整版)

Part1:2022年上海大学真题题目 学硕836 专硕915 Part2:2022年上海大学真题答案 学硕836 专硕915

问题和答案-内存泄露

1.看看Java内存模型,Java加载机制。平常写代码注意就行了。 2.  该销毁 销毁 该释放 释放 3,     4. 是死循环造成的内存溢出 还是啥没释放 造成 的内存泄露 5. 死循环你内存有多少够开销的? 6.静态的东西多注意就好了 7.生命周期长的类不要持有短周期的引用。 8.         9.

监控平台总结之面试常问答案

思路 延伸的面试题总结及答案: 1.说说前端监控平台/监控SDK架构设计和难点亮点? 架构设计 数据采集层: SDK: 在前端集成的 SDK 负责采集数据,包括性能指标、用户行为、错误日志等。 数据收集: 实现高效的数据采集机制,支持实时数据传输,可能使用 fetch、XHR 或 Beacon 等 API。 数据处理层: 数据传输: 数据通过 HTTP 或 WebSocket 发

【linux mysql】mysql高版本8.0.23版本密码修改总结

mysql 8.0 版本,由于增加了一些安全策略等限制,所以修改用户密码会稍微麻烦些。下面是针对这个高版本的总结。 一、配置/etc/my.cnf 文件 免密码登录mysql vim /etc/my.cnf# 增加这两行命令skip-grant-tablesdefault-authentication-plugin=mysql_native_password 重启启动mysql se

社交平台找旅游搭子一起旅行靠谱吗?答案是不要太爽!

哈喽小伙伴们,今天要跟大家分享一个超级棒的小程序——咕哇找搭子!作为一个热爱自由行的人,最头疼的就是找不到志同道合的小伙伴。但自从用了这个咕哇小程序后,一切都变得简单又充满乐趣啦!🎉 上个月,我计划去云南旅行,就试着在咕哇上发布了我的行程信息。没想到很快就收到了几位朋友的回应,其中一位叫小莲的朋友特别投缘。我们不仅目的地一样,就连兴趣爱好都出奇地相似,于是我们就决定一起出发啦!👭