8000 The value of the ctx->backend pointer has been accidentally modified, leading to a Use-After-Free (UAF) vulnerability · Issue #749 · stephane/libmodbus · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

The value of the ctx->backend pointer has been accidentally modified, leading to a Use-After-Free (UAF) vulnerability #749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
balckgu1 opened this issue May 29, 2024 · 3 comments

Comments

@balckgu1
Copy link

libmodbus version

libmodbus v3.1.6

OS and/or distribution

Ubuntu 18

Environment

...

Description

A UAF vulnerability exists in unit-test-server that is triggered when a specific message is sent to unit-test-server. The vulnerability appears to be caused by the ctx->backend pointer at line 171 in modbus.c being incorrectly modified after multiple calls or used after free.

Actual behavior if applicable

==7657==ERROR: AddressSanitizer: SEGV on unknown address 0x605ffffffe90 (pc 0x56a769c5088e bp 0x7ffdc458eb90 sp 0x7ffdc458e900 T0)

Expected behavior or suggestion

no crash

Steps to reproduce the behavior (commands or source code)

  1. Compile the program with the -g parameter
  ./autogen.sh
  ./configure --enable-static CC="clang -fsanitize=address  -O1 -g" CXX="clang -fsanitize=address  -O1 -g"
   make -j8
   clang -g -fsanitize=address -O1  unit-test-server.c -o unit-test-server -I ../src/ ../src/.libs/libmodbus.a
  1. send POC
    POC:
    poc.zip
  2. Then, you can see:
  ./unit-test-server 
The client connection from 127.0.0.1 is accepted
Waiting for an indication...
<00><00><00><00><00><0D><FF><03><01><62><00><01>
[00][00][00][00][00][05][FF][03][02][00][00]
Waiting for an indication...
<00><00><00><00><00><0D><FF><17><01><62><00><01><00><68><00><01><02><AA><BD>
AddressSanitizer:DEADLYSIGNAL
=================================================================
==17777==ERROR: AddressSanitizer: SEGV on unknown address 0x605ffffffe90 (pc 0x5cb30486d88e bp 0x7ffcb0ba2480 sp 0x7ffcb0ba21e0 T0)
==17777==The signal is caused by a WRITE memory access.
    #0 0x5cb30486d88e  (/home/XXX/libmodbuspoc/tests/unit-test-server+0xb88e)
    #1 0x5cb304869630  (/home/XXX/libmodbuspoc/tests/unit-test-server+0x7630)
    #2 0x7be8b1629d8f  (/lib/x86_64-linux-gnu/libc.so.6+0x29d8f)
    #3 0x7be8b1629e3f  (/lib/x86_64-linux-gnu/libc.so.6+0x29e3f)
    #4 0x5cb3048684c4  (/home/XXX/libmodbuspoc/tests/unit-test-server+0x64c4)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/home/XXX/libmodbuspoc/tests/unit-test-server+0xb88e) 
==17777==ABORTING
Aborted

libmodbus output with debug mode enabled

The location of the vulnerability can be further determined through gdb debugging:
Breakpoint at line 171 of modbus.c and run:

(gdb) run < /POC
Starting program: /unit-test-server < /POC
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
[New Thread 0x7ffff7bff640 (LWP 17164)]
[New Thread 0x7ffff73fe640 (LWP 17165)]
[Thread 0x7ffff7bff640 (LWP 17164) exited]
The client connection from 0.0.0.0 is accepted
Waiting for an indication...
<00><00><00><00><00><0D><FF><03><01><62><00><01>

Thread 1 "unit-test-serve" hit Breakpoint 1, send_msg (ctx=ctx@entry=0x5555555612a0, msg=msg@entry=0x7fffffffd8c0 "", msg_length=msg_length@entry=11) at modbus.c:171
171	    msg_length = ctx->backend->send_msg_pre(msg, msg_length);

The first time a breakpoint is hit, check the variable information:

(gdb) print ctx->backend
$7 = (const modbus_backend_t *) 0x55555555fce0 <_modbus_tcp_backend>

next

(gdb) next
173	    if (ctx->debug) {
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
175	            printf("[%.2X]", msg[i]);
(gdb) next
174	        for (i = 0; i < msg_length; i++)
(gdb) next
176	        printf("\n");
(gdb) next
[00][00][00][00][00][05][FF][03][02][00][00]
182	        rc = ctx->backend->send(ctx, msg, msg_length);
(gdb) next
�183	        if (rc == -1) {
(gdb) next
202	    if (rc > 0 && rc != msg_length) {
(gdb) next
208	}
(gdb) next
modbus_reply (ctx=<optimized out>, req=<optimized out>, req_length=<optimized out>, mb_mapping=<optimized out>) at modbus.c:1003
1003	}
(gdb) print ctx->backend
value has been optimized out
(gdb) info args
ctx = <optimized out>
req = <optimized out>
req_length = <optimized out>
mb_mapping = <optimized out>
(gdb) next
main (argc=1, argv=0x7fffffffdba8) at unit-test-server.c:184
184	        if (rc == -1) {
(gdb) next
113	    for (;;) {
(gdb) next
114	        do {
(gdb) next
115	            rc = modbus_receive(ctx, query);
(gdb) next
Waiting for an indication...
<00><00><00><00><00><0D><FF><17><01><62><00><01><00><68><00><01><02><AA><BD>
117	        } while (rc == 0);
(gdb) print ctx
$8 = (modbus_t *) 0x5555555612a0
(gdb) print ctx->backend
$9 = (const modbus_backend_t *) 0x55555555fce0 <_modbus_tcp_backend>
(gdb) next
121	        if (rc == -1 && errno != EMBBADCRC) {
(gdb) print ctx
$10 = (modbus_t *) 0x5555555612a0
(gdb) print ctx->backend
$11 = (const modbus_backend_t *) 0x55555555fce0 <_modbus_tcp_backend>
(gdb) next
127	        if (query[header_length] == 0x03) {
(gdb) next
183	        rc = modbus_reply(ctx, query, rc, mb_mapping);
(gdb) print ctx
$12 = (modbus_t *) 0x5555555612a0
(gdb) print ctx->backend
$13 = (const modbus_backend_t *) 0x55555555fce0 <_modbus_tcp_backend>

On the second hit, the pointer is modified and the program crashes:

(gdb) next

Thread 1 "unit-test-serve" hit Breakpoint 1, send_msg (ctx=ctx@entry=0x5555555612a0, msg=msg@entry=0x7fffffffd8c0 "", msg_length=msg_length@entry=11) at modbus.c:171
171	    msg_length = ctx->backend->send_msg_pre(msg, msg_length);
(gdb) print ctx
$14 = (modbus_t *) 0x5555555612a0
(gdb) print ctx->backend
$15 = (const modbus_backend_t *) 0x55555555aabd <modbus_new_rtu+285>
(gdb) next

Thread 1 "unit-test-serve" received signal SIGSEGV, Segmentation fault.
0x0000555555556cfd in send_msg (ctx=ctx@entry=0x5555555612a0, msg=msg@entry=0x7fffffffd8c0 "", msg_length=msg_length@entry=11) at modbus.c:171
171	    msg_length = ctx->backend->send_msg_pre(msg, msg_length);
(gdb) next
Couldn't get registers: No such process.
8000
@BrunoVernay
Copy link

@psychon
Copy link
psychon commented Jul 16, 2024

Sorry that I missed this one before. It's yet another duplicate of your other reports (#748 and #750).

Your reproduction instructions are missing a cd tests after make -j8. For the bisection, I went with the following command (executed in tests/): make -j9 -C .. && clang -g -fsanitize=address -O1 unit-test-server.c -o unit-test-server -I ../src/ ../src/.libs/libmodbus.a && echo a && ./unit-test-server

The result with commit bd1c85f is:

The client connection from 127.0.0.1 is accepted
Waiting for an indication...
<00><00><00><00><00><0D><FF><03><01><62><00><01>
[00][00][00][00][00][05][FF][03][02][00][00]
Waiting for an indication...
<00><00><00><00><00><0D><FF><17><01><62><00><01><00><68><00><01><02><AA><BD>
AddressSanitizer:DEADLYSIGNAL
=================================================================
==11633==ERROR: AddressSanitizer: SEGV on unknown address 0x505ffffffef0 (pc 0x55d24949a1d0 bp 0x7ffe575ba770 sp 0x7ffe575ba680 T0)
==11633==The signal is caused by a WRITE memory access.
    #0 0x55d24949a1d0 in modbus_reply /tmp/libmodbus/src/modbus.c:980:46
    #1 0x55d249495d31 in main /tmp/libmodbus/tests/unit-test-server.c:183:14
    #2 0x7f7d77ab2c89 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #3 0x7f7d77ab2d44 in __libc_start_main csu/../csu/libc-start.c:360:3
    #4 0x55d2493bf460 in _start (/tmp/libmodbus/tests/unit-test-server+0x21460) (BuildId: c323aee44c82f836315679df2710cd833be0facc)

The result with commit b4ef4c1 is:

The client connection from 127.0.0.1 is accepted
Waiting for an indication...
<00><00><00><00><00><0D><FF><03><01><62><00><01>
[00][00][00][00][00][05][FF][03][02][00][00]
Waiting for an indication...
<00><00><00><00><00><0D><FF><17><01><62><00><01><00><68><00><01><02><AA><BD>
Illegal data read address 0x163 or write address 0x68 write_and_read_registers
[00][00][00][00][00][03][FF][97][02]
Waiting for an indication...
ERROR Connection timed out: select
<00><01><02>Quit the loop: Connection timed out

git bisect thus concludes again:

b4ef4c17d618eba0adccc4c7d9e9a1ef809fc9b6 is the first bad commit
commit b4ef4c17d618eba0adccc4c7d9e9a1ef809fc9b6
Author: Michael Heimpold <mhei@heimpold.de>
Date:   Sat Jan 8 20:00:50 2022 +0100

    modbus_reply: fix copy & paste error in sanity check (fixes #614)
    
    While handling MODBUS_FC_WRITE_AND_READ_REGISTERS, both address offsets
    must be checked, i.e. the read and the write address must be within the
    mapping range.
    
    At the moment, only the read address was considered, it looks like a
    simple copy and paste error, so let's fix it.
    
    Signed-off-by: Michael Heimpold <mhei@heimpold.de>

 src/modbus.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

@stephane
Copy link
Owner

Thank you for your reports @balckgu1. It's important to run such analysis on dev version or at least on lastest release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants
0