近期有一台开了3389(远程桌面)的笔记本出现无法链接的情况。其具体状况是重启之后一段时间内可以链接,然后“随机”时间后便无法链接,但是物理查看一下笔记本处于开机+联网状态。
经过再三的排查,发现导致远程桌面无法链接的原因是VPN向路由表中写入了一条192.168.0.0/16的路由记录,这导致内网中所有的流量均被发往了49开头的这个ip地址,这条路由记录有点太狠了,整个子网全部被重定向到了49这台机器,难怪远程桌面连不上。
所以写到此处,需求就出来了:当发现在设置192.168.0.0/16这条路由时拒绝设置。然而网上找了一圈,似乎没有现成的软件具备这个功能:(,木的办法了,自己动手丰衣足食。
劫持路由表的思路
首先我们要搞清楚,如何操作windows的路由表。而已知route.exe可以查看并设置路由表,那么我们只需要顺着route.exe的函数调用分析即可。经过快速的跟踪,发现route.exe设置路由表的调用路径如下:
总结一下就是:AddRoute -> AddIpv4Route -> NsiSetAllParameters
NsiSetAllParameters函数由nsi.dll导出, 经过逆向,调用路径如下图:
继续完善调用链: AddRoute -> AddIpv4Route -> NsiSetAllParameters -> NsiSetAllParametersEx -> NsiIoctl -> NsiOpenDevice
由以上调用链路可以猜测,route.exe最终是通过nsi.dll的NsiIoctl向某个驱动对象发送请求,从而达到设置路由表的目的的。具体是哪个设备呢?看一下NsiOpenDevice的逆向代码:
看来是\\\\.\\Nsi这个设备,即\\Device\\Nsi这个设备。所以设置windows路由表应该是这样的:
route.exe将解析后得到的各个参数按照一定的格式组织起来,然后通过ioctl code + buffer的形式通知\\Device\\Nsi设备,\\Device\\Nsi设备通过ioctl code知道调用的功能是设置路由表,然后按照约定的结构从传入的buffer中取出需要的字段,最终配置内核对象中路由表对应的对象。
回头看一下我们的需求:当发现在设置192.168.0.0/16这条路由时拒绝设置。因此,我们只需要Hook住对应的ioctl code分发函数,然后检查对应字段是否是192.168.0.0,如果发现是我们想要拒绝的ip地址,则整个分发函数返回失败即可达成我们的目的。
寻找关键数据结构
接下来关键问题就是分析出上述的“对应字段”在buffer的什么位置。
依然回到调用链,但是这次我们从头开始找。通过逆向得知AddRoute函数会解析route.exe命令行传入的目标ip地址(此处是192.168.0.0),然后通过某函数将string类型的IP地址,转换成in_addr类型,随后将该数据以第一个参数传递给AddIpv4Route函数:
而在AddIpv4Route函数中,将想要设置的ip地址传递给了a5a[1]这个对象,最后a5a作为输入参数传递给NsiSetAllParameters,而NsiSetAllParameters最终会调用NsiIoctl函数给设备\\Device\\Nsi传递ctrl code和buffer,此处的buffer即a5a这个数组:
而NsiSetAllParameters函数其实只是进一步将所有的输入参数,按照约定的数据结构进行封装,上图中封装后的InputBuffer即为最终传递给\\device\\Nsi设备的buffer。
总结一下:
- 路由的目标ip地址是一个in_addr结构
- 目标ip被存放在输入给驱动的buffer的如下位置:
(char *)buffer + sizeof(void *) * 6 + sizeof(void *) *1
上述公式, sizeof(void *) * 1 == a5a[1], sizeof(void *) * 6 == InputBuffer[6]
Coding Time
因此可以写出如下劫持用驱动(32位Win7测试通过,教学目的部分数据大小写死):
- #include
- #include
-
- #define _MAX_PATH 20
-
- typedef NTSTATUS (*pfnZwQueryInformationProcess)(
- IN HANDLE ProcessHandle,
- IN PROCESSINFOCLASS ProcessInformationClass,
- OUT PVOID ProcessInformation,
- IN ULONG ProcessInformationLength,
- OUT PULONG ReturnLength OPTIONAL
- );
- typedef UCHAR* (*pfnPsGetProcessImageFileName)(PEPROCESS pEprocess);
-
- PDRIVER_DISPATCH g_oldControlAddress = NULL;
- pfnZwQueryInformationProcess ZwQueryInformationProcess = NULL;
- pfnPsGetProcessImageFileName PsGetProcessImageFileName = NULL;
-
- VOID DriverUnload(PDRIVER_OBJECT DriverObject)
- {
- InterlockedExchange(
- (PLONG)&DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL],
- (LONG)g_oldControlAddress
- );
- }
-
- NTSTATUS HookNsiDeviceIOControl( PDEVICE_OBJECT pDeviceObject, PIRP pIrp ) {
- HANDLE hCurrentProcess = NULL;
- PIO_STACK_LOCATION pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);
- PEPROCESS pCurrentProcessEprocess= IoGetCurrentProcess();
-
- switch (pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode) {
- case 0x120013:
- if (pIrpStackLocation->Parameters.Read.Length != 0 && pIrp->UserBuffer) {
- int *userBufferP6 = (int*)(pIrp->UserBuffer) + 6;
- int *ipBufferP1 = (int *)(*userBufferP6) + 1;
- if (*ipBufferP1 == 0xa8c0) {
- IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- return STATUS_UNSUCCESSFUL;
- }
- }
- break;
- }
- return ((PDRIVER_DISPATCH)g_oldControlAddress)(pDeviceObject, pIrp);
- }
-
- NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) {
- NTSTATUS status;
- UNICODE_STRING uniDeviceName, uniRouteName;
- PFILE_OBJECT pFileObject;
- PDEVICE_OBJECT pDeviceObject;
-
- RtlInitUnicodeString(&uniRouteName, L\"ZwQueryInformationProcess\");
- ZwQueryInformationProcess = (pfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&uniRouteName);
- RtlInitUnicodeString(&uniRouteName, L\"PsGetProcessImageFileName\");
- PsGetProcessImageFileName = (pfnPsGetProcessImageFileName)MmGetSystemRoutineAddress(&uniRouteName);
-
- RtlInitUnicodeString(&uniDeviceName, L\"\\\\Device\\\\Nsi\");
- status = IoGetDeviceObjectPointer(
- &uniDeviceName,
- FILE_READ_DATA,
- &pFileObject,
- &pDeviceObject
- );
- if (NT_SUCCESS(status)) {
- ObDereferenceObject(pFileObject);
- if (!g_oldControlAddress) {
- g_oldControlAddress = pDeviceObject->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
- }
- InterlockedExchange(
- (PLONG)&pDeviceObject->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL],
- (LONG)HookNsiDeviceIOControl
- );
- pDeviceObject->DriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
- }
-
- return STATUS_SUCCESS;
- }
效果展示
将上述驱动模块加载后,使用route.exe添加路由表时效果如下:
可以看到如果要设置192.168.0.0这条路由会失败,但是设置其他路由正常。
打完收工~
","catalog":[{"text":"","parent":[],"level":"H2","position":0},{"text":"背景说明","parent":[],"level":"H2","position":0},{"text":"劫持路由表的思路","parent":[],"level":"H2","position":0},{"text":"寻找关键数据结构","parent":[],"level":"H2","position":0},{"text":"Coding Time","parent":[],"level":"H2","position":0},{"text":"效果展示","parent":[],"level":"H2","position":0}],"category":"逆向研究"},"articles":[{"id":"1026_D8APBPI5DL3E5FDV9AHCBUQIQ4","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"蓝屏Dump分析:INVALID_PROCESS_ATTACH_ATTEMPT","brief":"不知不觉,距离上次蓝屏分析文章已经过去快要一年的时间,近期收集到了一个比较有意思的dump文件,有一些值得一说的地方——本文将借着这个dump文件,较为深入","thumb":{"ext":"png","height":113,"md5":"50412c85f71641ec5aa904ade9ba492f","name":"thumb","rotate":null,"size":6980,"thumb_source":"_Ob88uwsQOhD4BUmThZYMvQ","type":"image","width":200},"tags":["_control:readable_id:Dump-Analysis-BSOD-While-Attach-to-Exited-Process"],"create_time":"2024-09-18","modify_time":1728130901},{"id":"1026_BLNEPVDJEL1QN9MM3CKISLRNHG","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"在Linux下使用WinDDK编译Windows驱动程序","brief":"各位看官,请不要疑惑——因为就算笔者在打出这个标题的时候都有点困惑我为什么要做这么多此一举的事情。本博客曾多次提到,笔者的主力系统为Linux,因此有一些日","thumb":{"ext":"png","height":113,"md5":"35b22609c599c45edd76551a9e13b777","name":"thumb","rotate":null,"size":47315,"thumb_source":"_DlKyfCpMBPadzFhHjTHj6A","type":"image","width":200},"tags":["_control:readable_id:Compile-Windows-Drivers-with-WinDDK-under-Linux"],"create_time":"2024-08-31","modify_time":1725776967},{"id":"1026_5C20BUTOJ91LV4N91D2NF1NGB0","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"蓝屏Dump分析两例:PageFault与栈越界(DoubleFault)","brief":"近期手头收到了不少蓝屏崩溃的dump,其中有两个比较离谱所以特意将分析过程记录一下。接下来废话不多说,咱们直接开始。Page Fault首先祭出万能的!","thumb":{"ext":"png","height":113,"md5":"50412c85f71641ec5aa904ade9ba492f","name":"thumb","rotate":null,"size":6980,"thumb_source":"_BdV2Xv_9nom2cgWJeRpijw","type":"image","width":200},"tags":["_control:readable_id:Analyze-Two-Kernel-Dumps-PageFault-and-DoubleFault"],"create_time":"2023-12-30","modify_time":1703905298},{"id":"1026_6TKQBOTMK50575O1M7UAKSLI6G","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"Windows下构建基于OpenSSH+WSL的命令行工作环境","brief":"笔者的主力工作环境一直是Linux,但在一些场景下依然绕不开Windows系统,因此笔者家里有一台常年开机的Windows笔记本随时待命,当笔者有需求时会连","thumb":{"ext":"jpg","height":113,"md5":"d7c2d83a6455b1ef16039140b7f64ba0","name":"thumb","rotate":null,"size":4952,"thumb_source":"_apiaxALCgCgnOufUbljxWA","type":"image","width":200},"tags":["_control:readable_id:Build-Command-Line-Working-Environment-with-OpenSSH-and-WSL-on-Windows"],"create_time":"2023-07-19","modify_time":1717750359},{"id":"1026_LTOI22HTTD34BAJ7C2CISSIBGO","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"在K8s上构建Flink环境(Session高可用模式)","brief":"随着各种IT基础设施的发展与完善,各种管理、编排、计算框架被大量应用在日常的IT运维与开发中。本篇文章涉及的,是其中两位佼佼者:Kubernetes和Fli","thumb":{"ext":"png","height":113,"md5":"3f579849853694576183ae64d6c0411f","name":"thumb","rotate":null,"size":13657,"thumb_source":"_q58mtn4_4Rg2xZmwwjzRhA","type":"image","width":200},"tags":["_control:readable_id:Construct-Flink-HA-Cluster-on-Kubernetes"],"create_time":"2023-05-23","modify_time":1685446642},{"id":"1026_75EU40T2H97H548V16S8JN0C0S","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"多线程假象——记一次假多线程场景分析过程","brief":"多线程是我们日常开发中经常使用到的技巧,一般使用多线程的目的是为了加快某些操作的速度从而给用户更好的使用体验。近期笔者就遇到了一个多线程相关问题,本来是想加","thumb":{"ext":"png","height":113,"md5":"687fc39b73d9707b810994cd9894236d","name":"thumb","rotate":null,"size":16972,"thumb_source":"_Y-POGiBOZiDRpGnYbmvTFg","type":"image","width":200},"tags":["_control:readable_id:Multi-Thread-Illusion-Analyze-of-a-Fake-Multi-Thread-Situation"],"create_time":"2023-05-09","modify_time":1684149661},{"id":"1026_L8H5LKRV953E96MC3EE3C5EBFC","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"遍历FSD驱动派遣函数与Hook检测","brief":"FSD(File System Drivers)位于系统底层,是和磁盘驱动最近的地方。这个玩意平时存在感不强,但由于本身身处要地,所以经常被各种恶意程序、安","thumb":{"ext":"png","height":113,"md5":"f329e68331550f3eb606e37a06689655","name":"thumb","rotate":null,"size":5777,"thumb_source":"_OyLvBylqyTlscORf3RpUpw","type":"image","width":200},"tags":["_control:readable_id:iterate-fsd-driver-dispatch-function-and-detect-hooks"],"create_time":"2023-04-10","modify_time":1691122447},{"id":"1026_T8GSV9C35H6A33UVIJ2C7PVJU4","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"遍历内核已卸载模块","brief":"在恶意软件分析的过程中,我们不应该放过任何一处蛛丝马迹。细节是魔鬼,本文将介绍如何遍历windows内核中已卸载模块列表,让我们直捣恶意软件的最后一处藏身之","thumb":{"ext":"png","height":113,"md5":"3090d9f47770306924db85d8dd99742e","name":"thumb","rotate":null,"size":37660,"thumb_source":"_nkRro7Xk9pxM75meNMZ0LQ","type":"image","width":200},"tags":["_control:readable_id:iterate-unloaded-modules-in-windows-kernel"],"create_time":"2023-03-26","modify_time":1680054188},{"id":"1026_71VC6TA8UL17BEMN6LBHD1KB4G","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"GIMP抠图——蒙版法","brief":"博主平时比较喜欢看军事装备,近期逛壁纸站时发现了一张Su-35的图很好看,于是想把战斗机单独拿出来——也就是俗称的抠图。由于博客平时也需要弄一些配图,因此有","thumb":{"ext":"jpg","height":113,"md5":"4a092e61807b937306a0cb356bc27062","name":"thumb","rotate":null,"size":3596,"thumb_source":"_e8jypvl8Lx1P89lROPpYXw","type":"image","width":200},"tags":["_control:readable_id:Image-Matting-with-GIMP-using-Mask-Layer"],"create_time":"2023-01-18","modify_time":1736219250},{"id":"1026_1UQFO0G2UD2IB991R30SLKI774","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"遍历Windows系统DPC定时器","brief":"人是讨厌等待的动物,哪怕硬件响应慢个100毫秒,人类的血压都有可能会直线上升。而中断作为上古时期便随CPU一起出现的技术,承载着系统各种硬件本身的响应动作,","thumb":{"ext":"png","height":113,"md5":"ef9774d7299e26550c15c140b4f8e0a7","name":"thumb","rotate":null,"size":32610,"thumb_source":"_jrmItis_NKLdunhwJAE3Tw","type":"image","width":200},"tags":["_control:readable_id:Iterate-DPC-timers-from-Win7-to-Win11"],"create_time":"2022-12-17","modify_time":1671438048},{"id":"1026_GAV9PLR3VL5S3C7CJ2F66V4U44","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"SSDT & ShadowSSDT的遍历与Hook恢复","brief":"上一篇博文讨论了Windows 11下获取SSDT与ShadowSSDT表地址的问题,这篇博文我们来聊一下这两张表的遍历和Hook检测的问题。SSDT与S","thumb":{"ext":"png","height":113,"md5":"20c2b3fc9a2b00ab5f6f858c1a8e53ee","name":"thumb","rotate":null,"size":20707,"thumb_source":"_nxkivc-_HzpXYhblImlAtg","type":"image","width":200},"tags":["_control:readable_id:enumerate-and-restore-ssdt-or-shadowssdt-table"],"create_time":"2022-11-15","modify_time":1713072737},{"id":"1026_L1HHVSNE9P5PFAKU8RV4KAN0JK","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"Windows 11 SSDT & ShadowSSDT地址获取问题","brief":"近期有一个项目中需要遍历SSDT与ShadowSSDT,按照网上常规的readmsr(0xc0000082)方式获取这两张表的起始地址,Windows 7到","thumb":{"ext":"png","height":113,"md5":"20c2b3fc9a2b00ab5f6f858c1a8e53ee","name":"thumb","rotate":null,"size":20707,"thumb_source":"_fzbwp8wDBTHVNPNBh5IPzA","type":"image","width":200},"tags":["_control:readable_id:Windows-11-SSDT-and-ShadowSSDT-fetch-problem"],"create_time":"2022-10-31","modify_time":1667209561},{"id":"1026_S2QJR44JCD7O19ESK8VR8J5RF8","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"让群晖用上Let‘s Encrypt证书并设置自动更新","brief":"群晖的DSM默认带了一个Synology自签名证书,使用web访问时浏览器会提示网站是不受信任的网站。作为一个强迫症,这个可不能忍!于是花了点时间研究了一下","thumb":{"ext":"png","height":113,"md5":"921f9b6764c448fb592e36bbb33dc199","name":"thumb","rotate":null,"size":9176,"thumb_source":"_YiGgjeEzcf8Or8f0grN87A","type":"image","width":200},"tags":["_control:readable_id:setup-an-auto-update-letsencrypt-certificate-on-synology-dsm"],"create_time":"2022-09-05","modify_time":1728731433},{"id":"1026_QNELMQ8UQP4E3ECOK3TFNVRDHG","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"一文读懂PE文件签名并手工验证签名有效性","brief":"本文是 《一文读懂对称加密、非对称加密、哈希值、签名、证书、https之间的关系》 的姊妹篇(下文简称“姊妹篇”),在阅读本文之前,最好先阅读一下上一篇文章","thumb":{"ext":"png","height":113,"md5":"168e01c700894328e673659cd1532817","name":"thumb","rotate":null,"size":19144,"thumb_source":"_k-lqLmDVaUMDPCIlNPruYQ","type":"image","width":200},"tags":["_control:readable_id:one-article-to-understand-pe-signature"],"create_time":"2022-04-24","modify_time":1689826259},{"id":"1026_REDK1UEJSH5THFQNJQT43ECSPS","category_id":"1026_IDSH2LTE8H6OP77OV932E06N9S","category":"漏洞研究","title":"CVE-2014-1767 分析报告","brief":"NLE(Noob Learning Exploit)——油腻中年反病毒人员学漏洞系列,当然我更喜欢文艺版名字:朝花夕拾系列。因为入二进制逆向的坑,一开","thumb":{"ext":"png","height":112,"md5":"bc391f8876ec7fb67d141a0881baf827","name":"thumb","rotate":null,"size":39228,"thumb_source":"_PXCSr39Dm9Gu-5MHCiNbAg","type":"image","width":200},"tags":["_control:readable_id:NLE-Analyze-CVE-2014-1767"],"create_time":"2022-03-12","modify_time":1656504051},{"id":"1026_7UAKMJOIF11MR2QME8TPNJP0D0","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"一次由QQ浏览器性能分析引起的性能问题","brief":"这是一篇旧文,为博主供职于京东时由京东安全发表在各大平台的一篇文章。近期在整理电脑硬盘时发现躺在角落里的word文件,因此汇总到博客中来。背景最近数据泄","thumb":{"ext":"jpg","height":120,"md5":"e0592e8d06b130b41ab6499787b11f45","name":"thumb","rotate":null,"size":12803,"thumb_source":"_6QN0h_xLprL77H1B9DuqZw","type":"image","width":200},"tags":["_control:readable_id:analyse-a-performance-problem-caused-by-qq-browser"],"create_time":"2022-03-11","modify_time":1646963650},{"id":"1026_681RM3JRF15CR4IUHNERQMS5TO","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"Linux环境下使用Wine+IDA并激活Python插件","brief":"前言作为一名苦逼的反病毒人员,IDA是一个必不可少的工具,虽然IDA有Linux平台的版本,但其高昂的售价着实是让笔者望而却步,不过幸好Windows","thumb":{"ext":"png","height":112,"md5":"86fc980855dfb0e378aed420b53575f0","name":"thumb","rotate":null,"size":8229,"thumb_source":"_djUuAxWs-9EA8JHnfBdcWg","type":"image","width":200},"tags":["_control:readable_id:activate-IDAPython-with-wine-IDA-under-linux"],"create_time":"2022-01-20","modify_time":1702986941},{"id":"1026_SL1DJIURE52V3D1LV150PN3GH8","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"稳定暴力搜索EPROCESS结构获取系统进程列表","brief":"在安全领域内核开发的过程中,获取进程信息属于一个常见需求。由于存在潜在的对抗动作,笔者在项目中选择了遍历PspCidTable的技术方案——这样做","thumb":{"ext":"png","height":123,"md5":"05756abc35522f991770c04205baeef7","name":"thumb","rotate":null,"size":37292,"thumb_source":"_zoAGtXqmVcVYah913RwNHQ","type":"image","width":200},"tags":["_control:readable_id:stable-iterate-eprocess-structure-to-get-process-list"],"create_time":"2021-11-21","modify_time":1713231142},{"id":"1026_MFIC2A5KCP3TF6FFGE575RCFSG","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"一文读懂对称加密、非对称加密、哈希值、签名、证书、https之间的关系","brief":"文字作为人类特有的交流工具,伴随着整个人类的发展史。可以毫不夸张的说,没有文字人类不可能达到今天的科技成就。因此,人类一直在追求提高信息交流过程中的安全性—","thumb":{"ext":"png","height":113,"md5":"c0571989eddc62103f6b8616a3cea533","name":"thumb","rotate":null,"size":7421,"thumb_source":"_F6cTeH0G0AcrA8us51RXDg","type":"image","width":200},"tags":["_control:readable_id:one-article-to-understand-the-relationship-between-encryption-certificate-signature-https"],"create_time":"2021-11-01","modify_time":1714816834},{"id":"1026_R3ILENIKD91I1EUD7B89RE8B1G","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"[笔记] 使用ESXi搭建一个调试病毒的虚拟网络","brief":"在日常分析病毒样本的过程中,我们经常遇到需要调试蠕虫的情况。考虑到内网中的机器一般是不经常打补丁的,这种情况下我们一定需要注意网络隔离,不然有可能会出现蠕虫","thumb":{"ext":"png","height":89,"md5":"9a2bee6e695cc237453ed42ba48f0ec1","name":"thumb","rotate":null,"size":23631,"thumb_source":"_PcFPDoQb_V4CZBtopBTz0A","type":"image","width":200},"tags":["_control:readable_id:build-a-virus-debug-environment-with-ESXi"],"create_time":"2021-09-06","modify_time":1706783031},{"id":"1026_7V7MLRB3Q90SV8JF4TRBHF9EGK","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"[笔记] 学习K8S过程中遇到的坑","brief":"本文主要记录了笔者在学习和部署K8S容器的过程中遇到的一些问题,由于笔者不是专业的DevOps,因此可能涉及到一些错误,大家在参考的过程中请关注是否解决","thumb":{"ext":"png","height":105,"md5":"f19a447f19062bcb53d1622bc644f366","name":"thumb","rotate":null,"size":11770,"thumb_source":"_exKsP3B5aTm5NGkYRvF8Cg","type":"image","width":200},"tags":["_control:readable_id:problems-and-notes-during-learning-k8s"],"create_time":"2021-07-07","modify_time":1708874860},{"id":"1026_EDC0OQ139L0VD71N84UTGVJBK4","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"逆向群晖NoteStation用于博客后端","brief":"笔者的博客情节从高中时代开始,笔者就开始以各种各样的姿势折腾自己的博客:一开始用现成的博客网站,然后开始折腾wordpress一类的博客系统,再后来开","thumb":{"ext":"png","height":111,"md5":"eb364c47418ae2148c5f96e600624aa0","name":"thumb","rotate":null,"size":34233,"thumb_source":"_BQ1IM0PovtI3Ze5qN4b6UA","type":"image","width":200},"tags":["_control:readable_id:reverse-notestation-of-synology-nas"],"create_time":"2021-06-23","modify_time":1713235971},{"id":"1026_3K1SDBHN6P5HN5LDDHMMP6CA54","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"捉鬼记","brief":"(本文中所有人物均为虚构)告警初现“两只老虎爱跳舞…………”吴智明不耐烦的拿起手机按下了接听键。“喂,吴哥”,电话那头传来了公司运维小李","thumb":{"ext":"jpg","height":113,"md5":"c2e1677b5da770e37be37ad77c81f453","name":"thumb","rotate":null,"size":5020,"thumb_source":"_FUmuEF1pbQpYElA8HJqo8A","type":"image","width":200},"tags":["_control:readable_id:story-of-catch-a-ghost"],"create_time":"2021-05-20","modify_time":1656478682},{"id":"1026_S9K5LAAG8L6693AD4J05B2DTDG","category_id":"1026_OMRT425BFL0VNEIR50E5DKUJL4","category":"其他","title":"反弹Shell的一些姿势","brief":"纯BASH的方法下文中的/dev/tcp/ip/port是bash定义的一个虚拟文件,此文件一般不存在于磁盘之上, 详情可以参考bash的man手册.","thumb":{"ext":"png","height":120,"md5":"189085ffbaa527207addf16e42670e3a","name":"thumb","rotate":null,"size":20878,"thumb_source":"_t5bGnt1VCvUEN-UFx47bVg","type":"image","width":200},"tags":["_control:readable_id:skills-of-reverse-shell"],"create_time":"2021-05-08","modify_time":1634404644},{"id":"1026_DEO9V3RQH914R8PD5C10IMHTDO","category_id":"1026_IDSH2LTE8H6OP77OV932E06N9S","category":"漏洞研究","title":"V8老版本未公开漏洞分析","brief":"前言 近期大型互联网活动期间,作为苦逼的蓝队,“意外”截获到了一个通过某IM“0day”钓鱼的攻击事件。正好趁着五一假期闲来无事,在酒店写下近期研究这个","thumb":{"ext":"jpg","height":113,"md5":"82f5400be7e4837c55f0650b636106da","name":"thumb","rotate":null,"size":9592,"thumb_source":"_hVK8gcz1hn8NcASs5uoq3g","type":"image","width":200},"tags":["_control:readable_id:Analysis-of-undisclosed-vulnerabilities-in-older-versions-of-V8"],"create_time":"2021-04-20","modify_time":1706340205},{"id":"1026_C2SVQMRTOL20583PNUU24EB6NC","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"Route表添加劫持","brief":"背景说明近期有一台开了3389(远程桌面)的笔记本出现无法链接的情况。其具体状况是重启之后一段时间内可以链接,然后“随机”时间后便无法链接,但是物理查看一","thumb":{"ext":"jpg","height":113,"md5":"b3d197e4df65a3ee546c102d55d73767","name":"thumb","rotate":null,"size":13827,"thumb_source":"_DN6FbFs5e33LuVBuJL-BsQ","type":"image","width":200},"tags":["_control:readable_id:hijack-route-table-under-windows"],"create_time":"2021-03-01","modify_time":1635843738},{"id":"1026_QVUJMJKMRT43T9B2RQMAO3SC90","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"MageCart团伙新年期间开展攻击活动披露","brief":"概述近些年来,电子支付极大的方便了人们的生活,而疫情又提升了人们对电子支付的需求。随着电子支付应用场景、使用人数的增多,形形色色针对电子支付攻击也慢慢多了起来","thumb":{"ext":"png","height":74,"md5":"004d23c78c4421247a5665ccbc961199","name":"thumb","rotate":null,"size":9282,"thumb_source":"_iO6Oz9xAq_et8JfJCprVnw","type":"image","width":200},"tags":["_control:readable_id:MageCart-hacker-group-activities-within-Chinese-new-year"],"create_time":"2021-02-02","modify_time":1713248896},{"id":"1026_AE4RBIEFDP7MFFUG0D2VKT0QBG","category_id":"1026_EKGNQQLOP179197O09NPMDA524","category":"逆向研究","title":"通过紫狐木马聊聊注册表与文件系统过滤驱动","brief":"前言Dive into kernel系列,直译为深入内核系列,但我更喜欢他的另外一个名字:潜水系列,毕竟充分显示了笔者多年潜水不冒泡的功力;)扯远了,言归正","thumb":{"ext":"png","height":113,"md5":"c2332f3d9a526d84fdf3f02f491b2bae","name":"thumb","rotate":null,"size":53006,"thumb_source":"_Wd9Rwz3h56hQCHEVlMrtbQ","type":"image","width":200},"tags":["_control:readable_id:DIK-details-about-minifilter-with-analyse-of-zihu-trojan"],"create_time":"2020-12-29","modify_time":1714657328},{"id":"1026_RT3EFSNFM5631BU3U8T301Q6PK","category_id":"1026_KVFN6ROUUT6V94UFV7RN71BKT8","category":"友情链接","title":"友情链接","brief":"DarkRay's Blog一位自称是 \"网络安全爱好者\" 的渗透大佬。利鲨客安全团队(L.S.T)利鲨客安全团队(LyShark","thumb":{"ext":"png","height":50,"md5":"a6799076cf50ef2aeae512a65d5affca","name":"thumb","rotate":null,"size":13862,"thumb_source":"_W4jsc7isfwrIhKkJhQAWow","type":"image","width":260},"tags":["_control:readable_id:Links","_control:fullpage"],"create_time":"2000-01-01","modify_time":1735312474},{"id":"1026_EFE0CNR6QL1B771MKNH4E2G4EO","category_id":"1026_O38ONQHO7L65VFFIAP8VV2QKES","category":"关于我","title":"关于我","brief":"北漂社畜一枚。目前就职于某网络安全公司,初中开始接触网络安全。还记得当时《黑客X档案》、《黑客防线》、《非安全》期期必买,现在回想起来当初还是中国网络","thumb":{"ext":"jpg","height":113,"md5":"c47e9f2d03e0073dda916fedb749900c","name":"thumb","rotate":null,"size":7932,"thumb_source":"_xKS7iWVh8K32n4CgmeDoPA","type":"image","width":200},"tags":["_control:readable_id:about-me","_control:fullpage"],"create_time":"2000-01-01","modify_time":1706327825}],"page":{"total":3,"current":1,"max":10},"categories":["其他","关于我","逆向研究","漏洞研究","友情链接"],"archives":{},"endpoint":"http://127.0.0.1:3000","lang":"zh-CN","languages":["en-US","zh-CN"],"locale":{"Banner":"Debugwar","BTitle":"Watch & Learn","Slogan":"Step in or Step over, this is a problem ...","Index":"首页","Catalog":"目录","Archives":"归档","SwitchLanguage":"切换语言","CopyRight":"版权所有 (c) 2020 - 2025 Debugwar.com","DesignBy":"由 Hacksign 设计"}}Watch & Learn
Debugwar Blog
Step in or Step over, this is a problem ...

背景说明
近期有一台开了3389(远程桌面)的笔记本出现无法链接的情况。其具体状况是重启之后一段时间内可以链接,然后“随机”时间后便无法链接,但是物理查看一下笔记本处于开机+联网状态。
经过再三的排查,发现导致远程桌面无法链接的原因是VPN向路由表中写入了一条192.168.0.0/16的路由记录,这导致内网中所有的流量均被发往了49开头的这个ip地址,这条路由记录有点太狠了,整个子网全部被重定向到了49这台机器,难怪远程桌面连不上。
所以写到此处,需求就出来了:当发现在设置192.168.0.0/16这条路由时拒绝设置。然而网上找了一圈,似乎没有现成的软件具备这个功能:(,木的办法了,自己动手丰衣足食。
劫持路由表的思路
首先我们要搞清楚,如何操作windows的路由表。而已知route.exe可以查看并设置路由表,那么我们只需要顺着route.exe的函数调用分析即可。经过快速的跟踪,发现route.exe设置路由表的调用路径如下:
总结一下就是:AddRoute -> AddIpv4Route -> NsiSetAllParameters
NsiSetAllParameters函数由nsi.dll导出, 经过逆向,调用路径如下图:
继续完善调用链: AddRoute -> AddIpv4Route -> NsiSetAllParameters -> NsiSetAllParametersEx -> NsiIoctl -> NsiOpenDevice
由以上调用链路可以猜测,route.exe最终是通过nsi.dll的NsiIoctl向某个驱动对象发送请求,从而达到设置路由表的目的的。具体是哪个设备呢?看一下NsiOpenDevice的逆向代码:
看来是\\.\Nsi这个设备,即\Device\Nsi这个设备。所以设置windows路由表应该是这样的:
route.exe将解析后得到的各个参数按照一定的格式组织起来,然后通过ioctl code + buffer的形式通知\Device\Nsi设备,\Device\Nsi设备通过ioctl code知道调用的功能是设置路由表,然后按照约定的结构从传入的buffer中取出需要的字段,最终配置内核对象中路由表对应的对象。
回头看一下我们的需求:当发现在设置192.168.0.0/16这条路由时拒绝设置。因此,我们只需要Hook住对应的ioctl code分发函数,然后检查对应字段是否是192.168.0.0,如果发现是我们想要拒绝的ip地址,则整个分发函数返回失败即可达成我们的目的。
寻找关键数据结构
接下来关键问题就是分析出上述的“对应字段”在buffer的什么位置。
依然回到调用链,但是这次我们从头开始找。通过逆向得知AddRoute函数会解析route.exe命令行传入的目标ip地址(此处是192.168.0.0),然后通过某函数将string类型的IP地址,转换成in_addr类型,随后将该数据以第一个参数传递给AddIpv4Route函数:
而在AddIpv4Route函数中,将想要设置的ip地址传递给了a5a[1]这个对象,最后a5a作为输入参数传递给NsiSetAllParameters,而NsiSetAllParameters最终会调用NsiIoctl函数给设备\Device\Nsi传递ctrl code和buffer,此处的buffer即a5a这个数组:
而NsiSetAllParameters函数其实只是进一步将所有的输入参数,按照约定的数据结构进行封装,上图中封装后的InputBuffer即为最终传递给\device\Nsi设备的buffer。
总结一下:
- 路由的目标ip地址是一个in_addr结构
- 目标ip被存放在输入给驱动的buffer的如下位置:
(char *)buffer + sizeof(void *) * 6 + sizeof(void *) *1
上述公式, sizeof(void *) * 1 == a5a[1], sizeof(void *) * 6 == InputBuffer[6]
Coding Time
因此可以写出如下劫持用驱动(32位Win7测试通过,教学目的部分数据大小写死):
- #include
- #include
-
- #define _MAX_PATH 20
-
- typedef NTSTATUS (*pfnZwQueryInformationProcess)(
- IN HANDLE ProcessHandle,
- IN PROCESSINFOCLASS ProcessInformationClass,
- OUT PVOID ProcessInformation,
- IN ULONG ProcessInformationLength,
- OUT PULONG ReturnLength OPTIONAL
- );
- typedef UCHAR* (*pfnPsGetProcessImageFileName)(PEPROCESS pEprocess);
-
- PDRIVER_DISPATCH g_oldControlAddress = NULL;
- pfnZwQueryInformationProcess ZwQueryInformationProcess = NULL;
- pfnPsGetProcessImageFileName PsGetProcessImageFileName = NULL;
-
- VOID DriverUnload(PDRIVER_OBJECT DriverObject)
- {
- InterlockedExchange(
- (PLONG)&DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL],
- (LONG)g_oldControlAddress
- );
- }
-
- NTSTATUS HookNsiDeviceIOControl( PDEVICE_OBJECT pDeviceObject, PIRP pIrp ) {
- HANDLE hCurrentProcess = NULL;
- PIO_STACK_LOCATION pIrpStackLocation = IoGetCurrentIrpStackLocation(pIrp);
- PEPROCESS pCurrentProcessEprocess= IoGetCurrentProcess();
-
- switch (pIrpStackLocation->Parameters.DeviceIoControl.IoControlCode) {
- case 0x120013:
- if (pIrpStackLocation->Parameters.Read.Length != 0 && pIrp->UserBuffer) {
- int *userBufferP6 = (int*)(pIrp->UserBuffer) + 6;
- int *ipBufferP1 = (int *)(*userBufferP6) + 1;
- if (*ipBufferP1 == 0xa8c0) {
- IoCompleteRequest(pIrp, IO_NO_INCREMENT);
- return STATUS_UNSUCCESSFUL;
- }
- }
- break;
- }
- return ((PDRIVER_DISPATCH)g_oldControlAddress)(pDeviceObject, pIrp);
- }
-
- NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) {
- NTSTATUS status;
- UNICODE_STRING uniDeviceName, uniRouteName;
- PFILE_OBJECT pFileObject;
- PDEVICE_OBJECT pDeviceObject;
-
- RtlInitUnicodeString(&uniRouteName, L"ZwQueryInformationProcess");
- ZwQueryInformationProcess = (pfnZwQueryInformationProcess)MmGetSystemRoutineAddress(&uniRouteName);
- RtlInitUnicodeString(&uniRouteName, L"PsGetProcessImageFileName");
- PsGetProcessImageFileName = (pfnPsGetProcessImageFileName)MmGetSystemRoutineAddress(&uniRouteName);
-
- RtlInitUnicodeString(&uniDeviceName, L"\\Device\\Nsi");
- status = IoGetDeviceObjectPointer(
- &uniDeviceName,
- FILE_READ_DATA,
- &pFileObject,
- &pDeviceObject
- );
- if (NT_SUCCESS(status)) {
- ObDereferenceObject(pFileObject);
- if (!g_oldControlAddress) {
- g_oldControlAddress = pDeviceObject->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL];
- }
- InterlockedExchange(
- (PLONG)&pDeviceObject->DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL],
- (LONG)HookNsiDeviceIOControl
- );
- pDeviceObject->DriverObject->DriverUnload = (PDRIVER_UNLOAD)DriverUnload;
- }
-
- return STATUS_SUCCESS;
- }
效果展示
将上述驱动模块加载后,使用route.exe添加路由表时效果如下:
可以看到如果要设置192.168.0.0这条路由会失败,但是设置其他路由正常。
打完收工~
版权所有 (c) 2020 - 2025 Debugwar.com
由 Hacksign 设计