PWN Debugging and 1-day exploit development for CVE-2018-1160
Attachment download link: https://pwnable.tw/static/chall/netatalk.tgz + https://pwnable.tw/static/libc/libc-18292bd12d37bfaf58e8dded9db7f1f5da1192cb.so
It took about 1.5 days, and overall it was a very productive debugging and reproducing process. I learned some exploitation and debugging techniques, and it was very helpful for expanding my mindset.
The discovery process of the vulnerability is explained clearly by the author in Exploiting an 18 Year Old Bug. A Write-up for CVE-2018–1160 | by Jacob Baines, which is very interesting. You can also find a translated version at Discovery and Exploitation of Netatalk CVE-2018-1160_c01dkit's Blog-CSDN Blog.
The author mentioned in their blog that this vulnerability can only be exploited on NAS with -no-pie
. However, the creator of the HITCON 2019 challenge, DDAA, provided an exploit approach in HITCON CTF 2019 Pwn 371 Netatalk (ddaa.tw), which basically involves leveraging the nature of fork where child processes do not change the memory layout — in other words, ASLR plays a very minor role (laughs). This way, we can expose a valid address through a side channel and then exploit it.
0x01 Environment Setup
Setting up the environment was an extremely difficult task, and about half a day was spent pondering over the environment setup.
Let's directly talk about the final solution: based on the libc version, I made modifications using skysider/pwndocker: A docker environment for pwn in CTF (github.com) and then ran it in a docker container. The kernel version was challenging to resolve, and I couldn't compile the 4.9.0
kernel in WSL2 even after numerous attempts. However, since the kernel only affects the offset of chunk allocation through mmap, we can ignore this in the local environment.
FROM ubuntu:18.04
RUN dpkg --add-architecture i386 && \
apt-get -y update && \
apt install -y \
libc6:i386 \
libc6-dbg:i386 \
libc6-dbg \
lib32stdc++6 \
g++-multilib \
cmake \
ipython3 \
vim \
net-tools \
iputils-ping \
libffi-dev \
libssl-dev \
python3-dev \
python3-pip \
build-essential \
ruby \
ruby-dev \
tmux \
strace \
ltrace \
nasm \
wget \
gdb \
gdb-multiarch \
gdbserver \
netcat \
socat \
git \
patchelf \
gawk \
file \
python3-distutils \
bison \
rpm2cpio cpio \
zstd
COPY afpd /
COPY afp.conf /
COPY libatalk.so.18 /
USER 0000:0000
EXPOSE 5566
EXPOSE 1234
ENV LD_LIBRARY_PATH=/
CMD ./afpd -d -F ./afp.conf
sudo docker rm pwnable
sudo docker rmi pwnable:cve-2018-1160
sudo docker build . -t pwnable:cve-2018-1160
sudo docker run -dit -p 5566:5566 -p 1234:1234 --name pwnable pwnable:cve-2018-1160
0x02 Vulnerability Analysis
After opening afpd
in IDA and observing the strings, we can determine the version of netatalk
, and downloading the source code can help with further analysis.
Before that, you may need to understand about Data Stream Interface - Wikipedia
According to the blog, we can directly locate the vulnerable function.
You can observe that dsi->commands
is user-controllable, and the size in the memcpy
operation is controlled by dsi->commands[i]
.
After that, the server will try to reply with dsi->server_quantum
.
By observing the DSI structure
typedef struct DSI {
// structure fields
}
It is evident that dsi->commands[i]
is a uint8
type value, allowing us to write a maximum of 0xff
bytes, thus controlling attn_quantum
, datasize
, server_quantum
, serverID
, clientID
, commands
, and parts of data
(DSI_DATASIZ
= 65536
).
Finally, let's take a look at the operations on commands
.
Now, let's consider the exploit phase.
Exploitation
Address Bruteforcing
In an environment with ASLR enabled, the first thing we need to do is obtain the base address of libc
(or other useful addresses). This can be easily achieved under the condition of forking a child process.
Based on the above analysis, if the address the server wants to send back is placed in an illegal memory, it will cause an error and exit. This means we can determine a legitimate address by whether there is feedback. By using a side-channel, we can bruteforce and obtain a valid address.
A simple script for address bruteforcing:
# Address bruteforcing script
# Script code goes here
Attack Strategy
In the local environment, we can directly use the known offset for ease of debugging.
Once we know the libc
version and the offset, we can find the necessary gadgets. The challenge lies in achieving RCE with only one arbitrary write operation.
In an unchanged environment, we can exploit the _rtld_global
table in ld.so
, specifically targeting _dl_load_lock (_rtld_global+3840)
, and overwrite it with system
, with rdi
pointing to _dl_rtld_lock_recursive (_rtld_global+2312)
. These two are 0x600
bytes apart, which can be written in the Total data length
field.
Afterwards, we can bounce a shell to gain control (which should work).
# Exploit script using locally known data
# Script code goes here
References
Learning Pwn with Xu: Pwnable.tw CVE-2018-1160 | Clang Tailor Shop (xuanxuanblingbling.github.io)11/06/netatalk/
pwnable.tw CVE-2018-1160 | gtrboy's blog
CVE-2018-1160 netatalk Buffer Overflow Vulnerability Reproduction and Analysis | Ama2in9
Netatalk CVE-2018–1160 Buffer Overflow Vulnerability Analysis - Knownsec Community (aliyun.com)
This Content is generated by ChatGPT and might be wrong / incomplete, refer to Chinese version if you find something wrong.