前情回顾:
线程老哥执行memcpy越界访问溢出,堆栈里的一众对象难逃噩运。
详情参见:堆栈里的悄悄话——智能指针
神秘的0xCC
“去吧,为了首领的伟大理想出发”
我是一段二进制代码shellcode,0xCC大人精心创造了我,一同诞生的还有一个HTML表单文件小P,我就栖身在小P的身上,随着一个POST请求,我们朝着目标奔去。
很快我们就抵达目的地,这是一个Linux帝国,无数的数据包在这里来来往往。
“这里可真热闹”
“嘘,先别说话,马上要经过防火墙,藏好了,可别被发现了”,小P一把捂住了我的嘴。
说完我们就来到了防火墙面前,当差的守卫查看了我们的源IP和端口,又看了目的IP和目的端口,接着瞟了一眼负载数据,当他望向我这边时,我紧张的大气都不敢出一声,把头深深的埋着。
守卫凶神恶煞的问到:“你是去80端口的?这里面装的是什么?”
“回大人的话,这里面是个HTML表单,这单业务比较急,还望大爷行个方便”,小P一边说一边悄悄给守卫的衣袖里塞了一些银两。
“走吧,放行!”,总算等来了守卫的这句话。
通过了安检,我俩被安排到了一个队列等待,一会儿,一个自称是Apache公司的线程大哥把我们取走了。
栈溢出 & Stack Cannary
线程大哥把我俩放到了一片陌生的区域。
“你等我一下,我去打听下情况”,小P叮嘱完我后,和隔壁一个对象聊了起来。
“我打听清楚了,这里是进程的堆区,你可还记得主人交代的任务吗?”,小P问我。
“当然记得,我是shellcode,我要获得执行机会,潜伏起来,和主人取得联系,等待下一步指示”
“嗯,很好,一会我会找机会让你获得执行机会,先等等”“你要怎么办到啊?”,我有点好奇。
“你看到那个线程的栈没?”,小P一边说一边给我指。顺着小P指的方向望去,我看到了他口中所说的栈,线程大哥正在旁边忙碌,一会push,一会儿pop。
“我看到了,你猜你是想用栈溢出攻击覆盖返回地址,劫持指令寄存器,让我获得执行机会吧?”,我转头看着小P。
“小子,知道的不少嘛!不过你只回答对了一半,咱这次没法覆盖返回地址来获得执行机会”
“哦,这却是为何”
小P又指向了线程栈,“你看,返回地址前面有个8字节数字,那个叫Stack Cannary,是Linux帝国抵御栈溢出攻击的手段”
“不就是8个字节的数字,有什么可怕的?”,我不屑一顾。
“可不要小瞧了它,当栈溢出数据被修改后,函数return时,在从栈中取出返回地址之前会检查它有没有被修改,一旦被发现修改过,进程就会终止,咱们的计划不就泡汤了吗?”
“这程序员还挺聪明的嘛!居然还做了检查”
“这可不是程序员做的,这是GCC编译器干的,只要编译的时候添加了-fstack-protector标记就会自动添加,对原来的程序代码是透明的”
听着小P的话,我陷入了沉思。
C++虚函数表
“如此一来,那岂不是不能使用栈溢出了?”
“也不尽然。直接覆盖返回地址是基本不太可能了,过不了函数返回时的检查。但可以在它做检查之前就动手,抢先一步劫持执行流程,就没有机会做检查了。”,说完小P朝我眨了眨眼睛。
还有这种操作,我还是第一次听说,“不覆盖返回地址怎么能劫持到执行流程呢?你打算怎么做?”
“嘘!线程大哥来了!”我一下趴着不敢动弹,余光中瞥见线程大哥取出了隔壁对象的前面8个字节后就离开了。
“好险,差点被发现,你呀,说话别那么大声,计划败露那就全完了,知道吗!”,小P把我训了一顿。
“好啦,我知道了。我刚才问你的问题你还没回答我呢”,这一次我压低了音量。
“你猜刚刚线程大哥过来读取的是什么?”小P神秘地说。
“不是取的隔壁对象的内容吗?你也看到了啊还问我”
“这我当然知道,我是问你那内容是什么?”
“这我怎么知道,我又不知道那是个什么对象”
小P用手臂把我的头挽在胸前,在我耳边轻轻说到:“他读取的应该是对象的虚函数表指针,你看线程大哥读完内容后,又去这内容指向的地方了,你再看那里有一个表格,表格里每一项都是一个函数的地址”我按他说的看过去,果如他所言,只见线程大哥读取了表格中的一项后转身就去执行那里的代码了。
“你饶了半天,还没告诉我你打算怎么让我获得执行机会呢”,我又一次提出了我的疑问。
“你别着急啊,这秘诀就在这虚函数表指针上。你再看看线程栈,瞧见没有,那里也有一个对象,咱只要把它的虚函数表指针覆盖,待会儿线程大哥调用它的方法时,来读取的地址,我就安排成你的地址,就能让你有机会执行了”
我脑子飞速运转想象了一下这幅画面:
“果然是妙招!不过你怎么知道对象的虚函数表指针在哪里呢?”,我向小P提出了疑问。
“虚表指针一般都是在对象的头部,也就是最前面8个字节”
“所有对象都是吗?”小P摇摇头,“那倒也不是,有些对象所属的类根本没有虚函数,那也就没有虚函数表,虚表指针更是无从谈起了。不过这个对象是有的,主人在创造我们时已经都提前研究好了。咱们只需静待时机,按计划行事即可。”
DNS隐蔽通信
“快醒醒,该我们上了”,小P把我叫醒,不知过了多少时间, 我竟然睡着了。
只见线程大哥执行了memcpy,把我和小P一起复制到了栈里。
我昏沉的脑袋一下子清醒了过来,下意识的看了一下之前那对象,现在他就在我上面不远处,已经被小P的身体覆盖掉了,再仔细一看这对象的前8个字节,指向的函数表就在我的头顶,而表中每一项都指向了我所在的地址,0xCC大人果然安排的天衣无缝。
果不出乎所料,按照周密的计划,我终于等来了执行的机会,潜伏这么久,总算是可以活动活动了。
“你在干嘛?”,小P大声喝住了我。
“按照计划,我在和0xCC大人联系啊”
“你就这样直接建立网络连接吗?一会儿防火墙就会发现了”,小P面色凝重。
我有点不解,“那要怎么办?我怎么和大人联系上?”
“临行前大人叮嘱我了,用DNS请求把数据带出去,把数据编码后作为请求的域名,分多片发出去”
按照小P的策略,我把通信内容先进行了一次加密,然后再使用base64编码后,拆成了三段,准备用三个DNS请求给发出去。
“等一下,你不能使用0xCC大人的IP作为目的IP地址,会被防火墙发现的,就使用这里默认的DNS服务器地址就好了”,小P又一次喝止了我。
“使用这里默认的DNS服务器地址,那大人怎么能收到消息呢?”,我有点纳闷。
“放心,路由器那里已经安排好了!”
未完待续·······
彩蛋
“咦,DNS数据包发送失败了!”
“应该是没有权限,快翻一下大人给你准备的Linux提权指南”
欲知后事如何,请关注后续精彩......
往期热门文章:
来源:https://www.cnblogs.com/xuanyuan/p/12293934.html