nf_tables自用模板


前言

还是先放这两张图:

说明

用于构造图1中的消息体,或者消息体中的一个nested_attr;

需要输入一个json文件,如果是构造一个nested_attr,则input.json文件应该是这个nested_attr的所有子消息的嵌套格式,每嵌套一层就要用一个dict,其余的int和str直接给出具体的内容,其中int会自动给转成大端序,示例如下:

{
"NFTA_SET_ELEM_KEY":{
"NFTA_DATA_VALUE":"aaaaaaaaaaaaaaaa"
},
"NFTA_SET_ELEM_DATA":{
"NFTA_DATA_VERDICT":{
"NFTA_VERDICT_CODE":0
}
}
}

运行:

python3 ./netlink.py --nest

最终输出是uint8_t 的数组格式的结果和nested_attr的长度:

如果想直接构造一个netlink的消息体,那么需要的json格式是首先一个大的dict总揽全局,然后每一个子消息就是其中的一个小项,如果需要nested_attr就嵌套一个dict,最终会套用生成nested_attr的代码,先照着生成一个nested_attr,然后把头部的4字节替换成\x01\x00\x00\x00,也就是struct nfgenmsg,此时family固定为1:

{
"NFTA_CHAIN_TABLE":"my_table",
"NFTA_CHAIN_NAME":"my_chain",
"NFTA_CHAIN_FLAGS":2,
"NFTA_CHAIN_HOOK":{
"NFTA_HOOK_HOOKNUM":1,
"NFTA_HOOK_PRIORITY":1
}
}

输出结果是uinit8_t数组的内容,以及消息体的长度:

代码

import json
from pwn import *
import sys

micro2val = {}
micro2val['NFTA_SET_ELEM_KEY'] = 1
micro2val['NFTA_SET_ELEM_DATA'] = 2
micro2val['NFTA_DATA_VALUE'] = 1
micro2val['NFTA_DATA_VERDICT'] = 2
micro2val['NFTA_VERDICT_CODE'] = 1
micro2val['NF_DROP'] = 0
micro2val['NONAME'] = 0
micro2val['NFTA_SET_ELEM_LIST_ELEMENTS'] = 3

micro2val['NFTA_HOOK_HOOKNUM'] = 1
micro2val['NFTA_HOOK_PRIORITY'] = 2

micro2val['NFTA_CHAIN_TABLE'] = 1
micro2val['NFTA_CHAIN_NAME'] = 3
micro2val['NFTA_CHAIN_HOOK'] = 4
micro2val['NFTA_CHAIN_FLAGS'] = 10

micro2val['NFPROTO_INET'] = 1 #整个消息体的类型通常就用这个

micro2val['56'] = 56

class NestAttr:
def __init__(self):
pass
def align(self, length:int)->int:
res = (length + 3)&(~3)
return res
def trans_val(self, val:int)->int:
code = p32(val)
rescode = b''
for c in code:
rescode = p8(c) + rescode
res = u32(rescode)
return res
def create_nest_attr(self, con:map, mytype:str):
res = b''
for contype in con:
val = con[contype]
print(contype, type(val))
if type(val) == dict:
subcon, sublen = self.create_nest_attr(val, contype)
res += subcon
elif type(val) == int:
res += p16(8) + p16(micro2val[contype]) + p32(self.trans_val(val))
elif type(val) == str:
res += p16(len(val)+4)+p16(micro2val[contype])+val.encode("iso-8859-1")
res = p16(len(res)+4) + p16(micro2val[mytype]) + res #一个nest_attr的len是data的len
return res, len(res)
def create_netlink(self, con:map):
res, length = self.create_nest_attr(con, 'NONAME')
res = b'\x01\x00\x00\x00'+res[4:]
return res, length

def get_nest_attr():
f = open("./input.json")
con = json.loads(f.read())
na = NestAttr()
res, length = na.create_nest_attr(con, 'NFPROTO_INET')
print(res)
if_first = True
for ch in res:
if if_first:
if_first = False
print(f"{'{'}{ch}", end='')
else:
print(f",{ch}", end='')
print('}')
print(length)

def get_netlink():
f = open("./input.json")
con = json.loads(f.read())
na = NestAttr()
res, length = na.create_netlink(con)
print(res)
if_first = True
for ch in res:
if if_first:
if_first = False
print(f"{'{'}{ch}", end='')
else:
print(f",{ch}", end='')
print('}')
print(length)

if __name__ == '__main__':
if "--nest" in sys.argv:
get_nest_attr()
elif "--netlink" in sys.argv:
get_netlink()

20250507更新

str补0关于8对齐:

然后如果是多个同type的attr,使用json会因为dict的键不能重复而导致只保留了最后一个,这里的改进是用@进行注释区分,在代码中会有一个切片将@后边的切掉:

代码如下:

import json
from pwn import *
import sys

micro2val = {}
micro2val['NFTA_SET_ELEM_KEY'] = 1
micro2val['NFTA_SET_ELEM_DATA'] = 2
micro2val['NFTA_DATA_VALUE'] = 1
micro2val['NFTA_DATA_VERDICT'] = 2
micro2val['NFTA_VERDICT_CODE'] = 1
micro2val['NF_DROP'] = 0
micro2val['NONAME'] = 0
micro2val['NFTA_SET_ELEM_LIST_ELEMENTS'] = 3

micro2val['NFTA_HOOK_HOOKNUM'] = 1
micro2val['NFTA_HOOK_PRIORITY'] = 2

micro2val['NFTA_CHAIN_TABLE'] = 1
micro2val['NFTA_CHAIN_NAME'] = 3
micro2val['NFTA_CHAIN_HOOK'] = 4
micro2val['NFTA_CHAIN_FLAGS'] = 10

micro2val['NFPROTO_INET'] = 1 #整个消息体的类型通常就用这个

micro2val['NFTA_RULE_TABLE'] = 1
micro2val['NFTA_RULE_CHAIN'] = 2
micro2val['NFTA_RULE_EXPRESSIONS'] = 4

micro2val['NFTA_LIST_ELEM'] = 1
micro2val['NFTA_EXPR_NAME'] = 1
micro2val['NFTA_HOOK_DEV'] = 3
micro2val['NFTA_CHAIN_TYPE'] = 7
micro2val['NFTA_DUP_SREG_DEV'] = 2
micro2val['NFTA_EXPR_DATA'] = 2
micro2val['NFTA_IMMEDIATE_DREG'] = 1
micro2val['NFTA_IMMEDIATE_DATA'] = 2

micro2val['NFTA_LOOKUP_SET'] = 1
micro2val['NFTA_LOOKUP_SREG'] = 2
micro2val['NFTA_LOOKUP_SET_ID'] = 4

micro2val['NFTA_SET_TABLE'] = 1
micro2val['NFTA_SET_NAME'] = 2
micro2val['NFTA_SET_ID'] = 10
micro2val['NFTA_SET_KEY_LEN'] = 5
micro2val['NFTA_SET_FLAGS'] = 3
micro2val['NFTA_SET_DATA_LEN'] = 7




class NestAttr:
def __init__(self):
pass
def align(self, length:int)->int:
res = (length + 3)&(~3)
return res
def trans_val(self, val:int)->int:
code = p32(val)
rescode = b''
for c in code:
rescode = p8(c) + rescode
res = u32(rescode)
return res
def create_nest_attr(self, con:map, mytype:str):
res = b''
for contype in con:
val = con[contype]
print(contype, type(val))
contype = contype.split("@")[0]
print("contype", contype)
if type(val) == dict:
subcon, sublen = self.create_nest_attr(val, contype)
res += subcon
elif type(val) == int:
res += p16(8) + p16(micro2val[contype]) + p32(self.trans_val(val))
elif type(val) == str:
newlen = self.align(len(val))
val = val.ljust(newlen, "\x00")
res += p16(len(val)+4)+p16(micro2val[contype])+val.encode("iso-8859-1")
res = p16(len(res)+4) + p16(micro2val[mytype]) + res #一个nest_attr的len是data的len
return res, len(res)
def create_netlink(self, con:map, family=1):
res, length = self.create_nest_attr(con, 'NONAME')
res = p32(family)+res[4:]
return res, length
def get_nest_attr():
f = open("./input.json")
con = json.loads(f.read())
na = NestAttr()
res, length = na.create_nest_attr(con, 'NFPROTO_INET')
print(res)
if_first = True
for ch in res:
if if_first:
if_first = False
print(f"{'{'}{ch}", end='')
else:
print(f",{ch}", end='')
print('}')
print(length)

def get_netlink():
f = open("./input.json")
con = json.loads(f.read())
na = NestAttr()
res, length = na.create_netlink(con)
print(res)
if_first = True
for ch in res:
if if_first:
if_first = False
print(f"{'{'}{ch}", end='')
else:
print(f",{ch}", end='')
print('}')
print(length)

if __name__ == '__main__':
if "--nest" in sys.argv:
get_nest_attr()
elif "--netlink" in sys.argv:
get_netlink()


文章作者: q1ming
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 q1ming !
  目录