appneta / tcpreplay

Pcap editing and replay tools for *NIX and Windows - Users please download source from
http://tcpreplay.appneta.com/wiki/installation.html#downloads
1.17k stars 268 forks source link

[Bug] tcprewrite——Multi floating pointer errors in fuzzing() at fuzzing.c:244 #610

Closed 14isnot40 closed 4 years ago

14isnot40 commented 4 years ago

Describe the bug Multi floating pointer error bugs were discovered in tcprewrite binary, during caculating the offset of the random segment. The issue can be triggered in the function fuzzing() at fuzzing.c:244,182,232.

To Reproduce Steps to reproduce the behavior: 1. Compile tcpreplay according to the default configuration

2. execute command

tcprewrite -i $poc -o /dev/null --fuzz-seed=42

poc can be found here.

Expected behavior An attacker can exploit this vulnerability by submitting a malicious pcap that exploits this issue. This will result in a Denial of Service (DoS) when the application attempts to process the file.

Screenshots

gef➤  set args -i id:000005,sig:08,src:000489,op:FA-havoc,rep:8 -o /dev/null --fuzz-seed=42
gef➤  r
Starting program: /usr/local/bin/tcprewrite -i id:000005,sig:08,src:000489,op:FA-havoc,rep:8 -o /dev/null --fuzz-seed=42

Program received signal SIGFPE, Arithmetic exception.
0x00000000004267ec in fuzzing (tcpedit=tcpedit@entry=0x6e9550, pkthdr=<optimized out>, pktdata=pktdata@entry=0x6d7238 <pktdata_buff>) at fuzzing.c:244
244         uint32_t offset = ((r >> 16) % (l4len - 1)) + 1;
[ Legend: Modified register | Code | Heap | Stack | String ]
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── registers ────
$rax   : 0x4197            
$rbx   : 0x00000000006e9e10  →  0x00000000006e9550  →  0x0000000000000001
$rcx   : 0xba2e8ba3        
$rdx   : 0x0               
$rsp   : 0x00007fffffffd820  →  0x00000000006ebc40  →  0x1f003a84e5df1ef8
$rbp   : 0x23              
$rsi   : 0x00000000006ebc62  →  0x9132b7e850004500
$rdi   : 0x7               
$rip   : 0x00000000004267ec  →  <fuzzing+12348> div r15d
$r8    : 0x1dd0a670        
$r9    : 0x4197            
$r10   : 0x7               
$r11   : 0x4197d490        
$r12   : 0x00000000006e9550  →  0x0000000000000001
$r13   : 0x4197d497        
$r14   : 0x1               
$r15   : 0x0               
$eflags: [CARRY parity adjust zero sign trap INTERRUPT direction overflow RESUME virtualx86 identification]
$cs: 0x0033 $ss: 0x002b $ds: 0x0000 $es: 0x0000 $fs: 0x0000 $gs: 0x0000 
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── stack ────
0x00007fffffffd820│+0x0000: 0x00000000006ebc40  →  0x1f003a84e5df1ef8    ← $rsp
0x00007fffffffd828│+0x0008: 0x00000000006e9e80  →  0x0000000000000001
0x00007fffffffd830│+0x0010: 0x0000080000000800
0x00007fffffffd838│+0x0018: 0x00000000006ebc4e  →  0x0040d8c634002045 ("E"?)
0x00007fffffffd840│+0x0020: 0x0000000000000000
0x00007fffffffd848│+0x0028: 0x00007fffffffd8f8  →  0x00007fffffffd900  →  0x000000004c33f185
0x00007fffffffd850│+0x0030: 0x00000000006ebc40  →  0x1f003a84e5df1ef8
0x00007fffffffd858│+0x0038: 0x00000000006d7238  →  0x00000000006ebc40  →  0x1f003a84e5df1ef8
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── code:x86:64 ────
     0x4267e3 <fuzzing+12339>  inc    DWORD PTR [rcx+rcx*4-0x18]
     0x4267e7 <fuzzing+12343>  xor    edx, edx
     0x4267e9 <fuzzing+12345>  shr    eax, 0x10
 →   0x4267ec <fuzzing+12348>  div    r15d
     0x4267ef <fuzzing+12351>  lea    r9d, [rdx+0x1]
     0x4267f3 <fuzzing+12355>  sub    r14d, r9d
     0x4267f6 <fuzzing+12358>  je     0x4239ac <fuzzing+508>
     0x4267fc <fuzzing+12364>  lea    rsp, [rsp-0x98]
     0x426804 <fuzzing+12372>  mov    QWORD PTR [rsp], rdx
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── source:fuzzing.c+244 ────
    239          break;
    240      }
    241      case FUZZING_CHANGE_MID_FF:
    242      {
    243          /* fuzz random-size segment inside the packet payload with 0xff */
                 // l4len=0x1
 →  244          uint32_t offset = ((r >> 16) % (l4len - 1)) + 1;
    245          uint32_t sgt_size = fuzz_get_sgt_size(r, l4len - offset);
    246          if (!sgt_size)
    247              goto done;
    248  
    249          memset(l4data + offset, 0xff, sgt_size);
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── threads ────
[#0] Id 1, Name: "tcprewrite", stopped, reason: SIGFPE
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── trace ────
[#0] 0x4267ec → fuzzing(tcpedit=0x6e9550, pkthdr=<optimized out>, pktdata=0x6d7238 <pktdata_buff>)
[#1] 0x409a7e → tcpedit_packet(tcpedit=0x6e9550, pkthdr=0x7fffffffd8f8, pktdata=0x6d7238 <pktdata_buff>, direction=TCPR_DIR_C2S)
[#2] 0x407904 → rewrite_packets(tcpedit=0x6e9550, pin=0x6d9290, pout=0x6eaa00)
[#3] 0x4032c3 → main(argc=<optimized out>, argv=<optimized out>)

Possible causes of vulnerabilities: When calculate the size of segment, the modulo operation (l4len-1) may equals to 0.

    case FUZZING_CHANGE_MID_FF:
    {
        /* fuzz random-size segment inside the packet payload with 0xff */
        uint32_t offset = ((r >> 16) % (l4len - 1)) + 1;
        uint32_t sgt_size = fuzz_get_sgt_size(r, l4len - offset);
        if (!sgt_size)
            goto done;

        memset(l4data + offset, 0xff, sgt_size);
        packet_changed = 1;
        break;
    }

When I audited the source code, I found several similar problems in the fuzzing.c file. Such in line 182

 uint32_t new_len = (r % ((l4len) - 1)) + 1;

line 232

uint32_t offset = ((r >> 16) % (l4len - 1)) + 1;

Besides, the static inline function fuzz_get_sgt_size also exists this problem, which may be called in fuzzing() function multi places.(although i didn't generate specific poc)

static inline int
fuzz_get_sgt_size(uint32_t r, uint32_t caplen)
{
    if (0 == caplen)
        return 0;

    if (caplen <= SGT_MAX_SIZE)
        /* packet too small, fuzzing only one byte */
        return 1;

    /* return random value between 1 and SGT_MAX_SIZE */
    return (1 + (r % (SGT_MAX_SIZE - 1)));
}

System (please complete the following information):  - OS version : Ubuntu 16.04  - Tcpreplay Version : 4.3.2/master branch

Additional Thanks to @fklassen for maintaining and patching tcpreplay-utils. I have carefully checked the issues I submitted in May(issue576-579), and they have been patched succesfully.

fklassen commented 4 years ago

Thanks for the bug report. It appears to be a duplicate of #570. Verified that this is fixed in 4.3.3-beta1.