The Power of Variant Analysis in Software Vulnerability Discovery
The Power of Variant Analysis in Software Vulnerability Discovery
fl
A glance of vulnerability&exploit market
Zerodium
A glance of vulnerability&exploit market
Zerodium
A glance of vulnerability&exploit market
天府杯
A glance of vulnerability&exploit market
天府杯
A glance of vulnerability&exploit market
• Static Analysi
• Dynamic Analysi
• Fuzzin
•…
g
fi
g
• Static Analysi
• Dynamic Analysi
• Fuzzin
• Variant analysis
g
Variant analysis
• Refers to the process of studying a known security bug and then looking
for code which is vulnerable in a similar wa
• Sounds easy?
Variant analysis
• Requires
Outline
• Introductio
• Conclusion
n
Background
• XNU is the OS kernel developed by Apple and used in iOS and macOS
product
close(sock); close(sock);
int sock;
struct sockaddr_un name;
char buf[1024];
/* Create socket from which to read. */
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
/* Create name. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, "1.txt");
name.sun_len = strlen(name.sun_path)
close(sock);
int sock;
struct sockaddr_un name;
char buf[1024];
/* Create socket from which to read. */
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
socket
/* Create name. */
name.sun_family = AF_UNIX; socket_common
strcpy(name.sun_path, "1.txt");
name.sun_len = strlen(name.sun_path) socreate_internal
/* Bind socket to the path. */ soalloc
bind(sock, (struct sockaddr *)&name,
SUN_LEN(&name)); unp_attach
/* Read from the socket. */
read(sock, buf, 1024);
close(sock);
…
/* Bind socket to the path. */
so_proto unp_socket
bind(sock, (struct sockaddr *)&name,
so_pcb unp_vnode
SUN_LEN(&name)); …
so_usecount
/* Read from the socket. */
read(sock, buf, 1024); struct protosw
…
close(sock); pr_lock a number of
pr_unlock function pointers
…
int sock;
struct sockaddr_un name; struct socket struct unpcb
char buf[1024];
/* Create socket from which to read. */ …
sock = socket(AF_UNIX, SOCK_DGRAM, 0); so_proto unp_socket
close(sock);
int sock;
struct sockaddr_un name;
char buf[1024];
/* Create socket from which to read. */
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
bind
/* Create name. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, "1.txt"); sobindlock
name.sun_len = strlen(name.sun_path)
socket_lock
/* Bind socket to the path. */
bind(sock, (struct sockaddr *)&name,
SUN_LEN(&name));
unp_bind
/* Read from the socket. */ socket_unlock
read(sock, buf, 1024);
close(sock);
close(sock);
/* Create name. */ …
name.sun_family = AF_UNIX; so_usecount
strcpy(name.sun_path, "1.txt");
name.sun_len = strlen(name.sun_path)
close(sock);
Race Condition
close(sock); close(sock);
fi
…
we can make a socket
so_proto unp_socket binding to two vnodes
so_pcb unp_vnode (two references)
…
so_usecount
struct vnode
VSOCK
v_socket
…
struct vnode
VSOCK
v_socket
…
/* Create name. */
name.sun_family = AF_UNIX;
strcpy(name.sun_path, "1.txt");
close
name.sun_len = strlen(name.sun_path)
soo_close
/* Bind socket to the path. */
bind(sock, (struct sockaddr *)&name, soclose
SUN_LEN(&name));
close(sock);
int sock;
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
Trigger UAF by connecting two names From the kernel point of view
;
…
so_proto unp_socket
so_pcb unp_vnode
…
so_usecount
struct vnode
VSOCK
0
…
struct vnode
VSOCK
v_socket
…
The dangling pointer in one of the vnodes will pass into socket_lock()
sock = socket(AF_UNIX, SOCK_DGRAM, 0)
sock2 = socket(AF_UNIX, SOCK_DGRAM, 0)
in parallel
bind(sock, (struct sockaddr *) &server1, bind(sock, (struct sockaddr *) &server2,
sizeof(struct sockaddr_un))) sizeof(struct sockaddr_un)))
close(sock
The x
• Fixed in iOS 12.
• Still raceable, but adding extra checks to make sure two vnodes will only
keep one reference to the socket
fi
2
Exploitation
Exploitation
fetch and
call a
function
pointer
through
two
deferences
to a freed
socket
Exploitation
fetch and
call a
function
pointer
through save a
two return
deferences address to
to a freed the freed
socket socket
Binary version may be better
• Please refer to our talk at Black Hat USA 2019 for more details regarding how to
exploit this vulnerability and bypass PAC
fl
fl
Outline
• Introductio
• Conclusion
n
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
Case 1: check the same patten in the same subsystem
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
check temporary unlocks in unp_connect
int sock;
struct sockaddr_un name;
char buf[1024]; connect
/* Create socket from which to write. */
sock = socket(AF_UNIX, SOCK_DGRAM, 0);
connectit
/* Create name. */
name.sun_family = AF_UNIX; socket_lock
strcpy(name.sun_path, "1.txt");
name.sun_len = strlen(name.sun_path);
soconnectlock
/* Connect the socket to the path. */
connect(sock, (struct sockaddr *)&name,
SUN_LEN(&name));
unp_connect
/* Write to the socket. */ socket_unlock
write(sock, buf, 1024);
close(sock);
socket_unlock
sonewconn
socket_lock
…
s
Normal execution
server socket
• A new socket object is created and
inserted into the server socket’s
so_comp queu so_proto
so_pcb
• so_incomp: q of partially
unaccepted conns
so_incomp
so_comp new socket
• so_comp: q of complete
unaccepted conns
e
The vulnerability
• The error handling code for race condition leads to a mistake
fl
Abnormal execution with race condition detected
so_proto
• Cleaning the so_incomp queue will try
to relock the socket objec so_pcb
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
ow-divert socket UAF
fl
fl
work ow
socket_lock
flow_divert_pcb_init
MALLOC_ZONE(new_pcb
new_pcb->so = so
socket_unlock
socket_lock
fl
Normal Execution
flow_divert_pcb
…
so
socket
Abnormal Execution under race condition
flow_divert_pcb two flow_divert_pcb pointing to
… the same socket, eventually
so
leading to socket UAF
socket
flow_divert_pcb
…
so Apple fixed the
issue in iOS 14
Case 3: check similar pattens in other subsystems
granularity of the vulnerability pattern
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
temporary unlocks in other subsystems
• More and more bugs caused by temporary unlocks were discovered, implying an
important bug pattern
• https://googleprojectzero.blogspot.com/2019/04/splitting-atoms-in-xnu.html
• https://blog.zimperium.com/ziva-video-audio-ios-kernel-exploit/
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
vsock race condition in the Linux kernel
• CVE-2021-26708
• by Alexander Popov
• vsk->transport may
be changed/freed by
another thread while
being used by current
thread
k
unsafe *_unlock
unsafe socket_unlock
search space
l i t y
rabi same subsystem other subsystems other operating systems
l ne
v u
w n
no
k
Conclusion
Thank you!