call_user_func

在官方文档中有这种用法

<?php

namespace Foobar;

class Foo {
    static public function test() {
        print "Hello world!\n";
    }
}

call_user_func(__NAMESPACE__ .'\Foo::test');
call_user_func(array(__NAMESPACE__ .'\Foo', 'test'));

?>

这个函数可以直接调用类中的静态方法,比如

call_user_func('Foo::test');

update注入

一种比较少见的sql注入

具体用法如下

如果不加where条件就能把整个字段的值都改掉,一般碰到改价格买东西的题目就会用到

如果碰到像上面这张情况可以用大小写同时用的方法绕过(不得不说对SQL注入的过滤用黑名单真的是很傻的办法= =)下面是一个payload示例

1';UPdATE%09items%09SeT%09price=1;#

%09是tab,堆叠+大小写混用就能用了

python urllib头注入

一个16年的漏洞,影响版本是python 2.7.16以下和python 3.7.3以下。

以下面这个场景为例

import urllib2
import sys
url=sys.argv[1]
result=urllib2.urlopen(url)
print result.read()

在url被赋值http://127.0.0.1时,服务端会接收到一个正常的http请求包。但如果赋值是http://127.0.0.1/%0d%0a123时,则会被换行插入一个123,如下图

漏洞原理是urllib在解析url时。接受URL编码的值。会包含在HTTP数据流中

因此我们就可以利用这点来实现对内网服务的CSRF,比如在内网的redis,就能通过这点来实现修改账号密码

python命令行参数接收

在看头部注入的wp时学到的,以下面这段代码为例

#1.py
import urllib2
import sys
url=sys.argv[1]
result=urllib2.urlopen(url)
print result.read()

在命令行中输入python 1.py http://127.0.0.1/,url的值就会被赋上http://127.0.0.1/

关于 Content-Type:application/x-www-form-urlencoded 和 Content-Type:multipart/related

这里记录一个链接 https://www.cnblogs.com/taoys/archive/2010/12/30/1922186.html

127.0.0.1和0.0.0.0的区别

直接上结论,127.0.0.1 是一个环回地址。并不表示“本机”。0.0.0.0才是真正表示“本网络中的本机”。

详情可以看这里

如果碰到下面这样的过滤

if(ip2long('127.0.0.0')>>24 == $int_ip>>24 || ip2long('10.0.0.0')>>24 == $int_ip>>24 || ip2long('172.16.0.0')>>20 == $int_ip>>20 || ip2long('192.168.0.0')>>16 == $int_ip>>16){
    echo "fali!";
}

就可以用0.0.0.0来绕过

parse_url与curl

这里记录一篇wp里看到的特性

dict协议

dict协议可以用来打ssrf,并且redis允许这一协议的访问

dict://serverip:port/命令:参数向服务器的端口请求为【命令:参数】,并在末尾自动补上\r\n(CRLF) 执行效果如下

主从复制

主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
redis的持久化使得机器即使重启数据也不会丢失,因为redis服务器重启后会把硬盘上的文件重新恢复到内存中,但是如果硬盘的数据被删除的话数据就无法恢复了,如果通过主从复制就能解决这个问题,主redis的数据和从redis上的数据保持实时同步,当主redis写入数据是就会通过主从复制复制到其它从redis。

python栈帧沙箱逃逸

最近刚接触这种特殊的沙箱逃逸,主要原理就是利用python自带的一种迭代器类型——生成器(generator)的gi_frame等栈帧属性的特性,配合f_back指向上一级调用栈帧的引用,从而达到栈帧逃逸的效果(更多内容可以看这里)。其中要记住一点是,如果要进行栈帧逃逸,在yield声明完一个生成器时就要先f_back一次,作用是构建调用栈,并不会回退。后续的f_back不管是直接加在声明后面还是在next获取对象后都可以

这里再记录一下f_code的一些变量:

  • co_varnames:这是一个包含函数的局部变量和参数名的元组。在函数的作用域内声明的变量名会按照它们出现的顺序被保存在这里。

  • co_names:一个包含函数中使用的变量名(不包括局部变量)的元组,例如在函数内部引用的全局变量或内置变量名。

  • co_consts:一个包含字节码中所有常量引用的元组,这些常量可能是字符串、数字、元组等不变类型。

除了与变量相关的属性,f_code 还包含了其他一些描述代码的属性:

  • co_argcount:函数的位置参数的数量。

  • co_kwonlyargcount:函数的仅限关键字参数的数量。

  • co_nlocals:函数中局部变量的数量。

  • co_stacksize:函数执行所需的栈的大小。

  • co_flags:描述函数的功能的标志的数字,例如是否是一个生成器函数。

  • co_code:编译过的函数字节码的字符串表示。

在2024 ciscn的mossfern中,就使用了co_consts变量读取沙箱外的常量,从而得到flag。还有一个比较巧妙的点是将回显内容中的flag转换成字符串类型后用空格分割每个字符,就能绕过过滤。payload如下

def waff():
    def f():
        yield g.gi_frame.f_back
    g = f()  
    frame = [x for x in g][0] 
    globals=frame.f_back.f_back.f_back.f_globals
    builtins=globals["_""_builtins_""_"]
    flag=frame.f_back.f_back.f_back.f_code.co_consts
    str=builtins.str
    flag=str(flag)
    for i in flag:
        print(i,end=" ")
waff()