前言
还是先放这两张图:


说明
用于构造图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 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 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()
|