超越ADMINISTRATOR

作者:陆麟
转载请征得作者同意.
2000.1.30


NT的安全组件里有一个叫Local Security Authority Protected Subsystem.当我们以ADMINISTRATOR登陆时,系统根据缺省的授权,赋予ADMINISTRATOR16个授权.下面乃是详细的清单.
 SeChangeNotifyPrivilege
 SeSecurityPrivilege
 SeBackupPrivilege
 SeRestorePrivilege
 SeSystemtimePrivilege
 SeShutdownPrivilege
 SeRemoteShutdownPrivilege
 SeTakeOwnershipPrivilege
 SeDebugPrivilege
 SeSystemEnvironmentPrivilege
 SeSystemProfilePrivilege
 SeProfileSingleProcessPrivilege
 SeIncreaseBasePriorityPrivilege
 SeLoadDriverPrivilege
 SeCreatePagefilePrivilege
 SeIncreaseQuotaPrivilege
其中 SeChangeNotifyPrivilege是缺省打开的.其他则需要调整TOKEN来打开.拥有了这么多的权限后,ADMIN真可谓强大,没有任何其他用户拥有这么多的权限了.但是,仍然有几个更有威力的权限没有赋予ADMIN.那就是SeTcbPrivilege和SeCreateTokenPrivilege. SeTcbPrivilege表示当前用户的操作代表了系统的操作,SeCreateTokenPrivilege更可赤裸裸地为任意令牌创建权限.乃是无上的特权.如果任何人拥有了这两个权限,在NT世界的权利就太夸张了.所以,NT根本就不给任何用户以这两个权限.
出于对权利的渴望,通常病毒,HACKER都会想法获取最高权限.现在,由于NT的保护,直接地获取这2个权限是不行了.那么就需要饶个弯子了.
由于没有直接的API可以增加TOKEN的特权,我们只好通过LSA POLICY库调整用户权限.因为用户权限在LSA POLICY库里被提取出来.当LSA POLICY库里增加了一个特权,用户可以在下一个进程里打开该特权.HEHE... ADMIN组对LSA POLICY库有写权.:DDD ADMIN没有超级特权,LSA对用户的特权从POLICY库里提取... 真是个可爱的连环套啊. :)
下面是我写的程序,打开ADMINISTRATOR的SeTcbPrivilege特权.尽管我在程序里面设置了ADMIN检查,但是通过少量的改写就可以时普通用户获取一些超级权限.:)里面的小技巧大家自己通常可以动出脑筋的.当然并不是通过删除ADMINISTRATOR检验就可以完成的. :)
当然,这里有编译好的版本供下载.
/*++
sec.cpp

  Written by Lu Lin. 2000.1.30

  A security program demo.
  Show Administrator's SID, and privileges.
  At last we add SE_TCB_NAME right to administrator.
  Of course, this right is almost useless to administrator,
  but you can port it for other users. :)
  You should logon as administrator for run this program
  though ADMIN group's authority is enough.
  Tip: We may get a authority beyound admin for a normal
  user through this demo by a small trick. Think about it
  yourself.:)
--*/

#define UNICODE
#include <windows.h>
#include <iostream.h>
#include <stdio.h>
#include <ntsecapi.h>

//
//Global vars
//
LSA_HANDLE PolicyHandle;
PSID Sid=0;
DWORD cbSid=0;
LPTSTR ReferencedDomainName=0;
DWORD cbReferencedDomainName=0;
SID_NAME_USE peUse;
PUNICODE_STRING UserRights=0; //UnicodeString Pointer to PRIVILEGE
ULONG Count=0; //
WCHAR textSid[200];
HANDLE token=0;
PTOKEN_PRIVILEGES TokenInformation=0;
BOOL owned=0;

//
//quit
//
void quit(int err){
 if (Sid) delete Sid;
 if (ReferencedDomainName) delete ReferencedDomainName;
 if (UserRights) delete UserRights;
 if (TokenInformation) delete TokenInformation;
 if (token) CloseHandle(token);
 if (PolicyHandle) LsaClose(PolicyHandle);

 wprintf(L"\n\nWritten by Lu Lin. 2000.1.30\nLicence: Freeware.\n");

 if (err){
  exit(0xc0000000);
 }
 else {
  exit(0);
 }
}

void printprivilege(LUID_AND_ATTRIBUTES* luid){
 WCHAR dispname[100];
 ULONG cb=100;

 if (!LookupPrivilegeName(
  0,
  &(luid->Luid),
  dispname,
  &cb)){
  wprintf(L"I can't translate SOME LUID to privilege!\n");
  exit(1);
 }

 wprintf(L"\tPrivilege: %s\n",dispname);

 if (!_wcsicmp(dispname,L"SeTcbPrivilege")) owned=1;

 switch (luid->Attributes){
 case SE_PRIVILEGE_ENABLED_BY_DEFAULT:
  wprintf(L"\t\tThis privilege is enabled by default\n");
  break;
 case SE_PRIVILEGE_ENABLED:
  wprintf(L"\t\tThis privilege is enabled.\n");
  break;
 case SE_PRIVILEGE_USED_FOR_ACCESS:
  wprintf(L"\t\tThis privilege is used for access.\n");
  break;
 case 3:
  wprintf(L"\t\tThis privilege is always on for you.\n");
  break;
 case 0:
  wprintf(L"\t\tThis privilege you owned has not been enabled yet.\n");
 }
}

void init(){
 WCHAR username[30];
 ULONG cb;
 OSVERSIONINFO osv;

 //if nt?
 ZeroMemory(&osv,sizeof(osv));
 osv.dwOSVersionInfoSize=sizeof(osv);
 GetVersionEx(&osv);
 if (!osv.dwPlatformId&VER_PLATFORM_WIN32_NT){
  wprintf(L"This program only runs on NT");
  quit(1);
 }

 //
 //Check if this thread is executed inside administrator's context.
 //
 cb=30;
 GetUserName(username,&cb);
 if (_wcsicmp(username,L"administrator")){
  wprintf(L"Logon as administrator first!\n");
  quit(1);
 }

 wprintf(L"WINDOWS NT %i.%i Build %i %s\n\n",
  osv.dwMajorVersion,
  osv.dwMinorVersion,
  osv.dwBuildNumber,
  osv.szCSDVersion);
}

BOOL GetTextualSid(
    PSID pSid,            // binary Sid
    LPTSTR TextualSid,    // buffer for Textual representation of Sid
    DWORD dwBufferLen // required/provided TextualSid buffersize
    )
{
    PSID_IDENTIFIER_AUTHORITY psia;
    DWORD dwSubAuthorities;
    DWORD dwSidRev=SID_REVISION;
    DWORD dwCounter;
    DWORD dwSidSize;

    // Validate the binary SID.

    if(!IsValidSid(pSid)) return FALSE;

    // Get the identifier authority value from the SID.

    psia = GetSidIdentifierAuthority(pSid);

    // Get the number of subauthorities in the SID.

    dwSubAuthorities = *GetSidSubAuthorityCount(pSid);

    // Compute the buffer length.
    // S-SID_REVISION- + IdentifierAuthority- + subauthorities- + NULL

    dwSidSize=(15 + 12 + (12 * dwSubAuthorities) + 1) * sizeof(TCHAR);

    // Check input buffer length.
    // If too small, indicate the proper size and set last error.

    if (dwBufferLen < dwSidSize)
    {
        SetLastError(ERROR_INSUFFICIENT_BUFFER);
        return FALSE;
    }

    // Add 'S' prefix and revision number to the string.

    dwSidSize=wsprintf(TextualSid, TEXT("S-%lu-"), dwSidRev );

    // Add SID identifier authority to the string.

    if ( (psia->Value[0] != 0) || (psia->Value[1] != 0) )
    {
        dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
                    TEXT("0x%02hx%02hx%02hx%02hx%02hx%02hx"),
                    (USHORT)psia->Value[0],
                    (USHORT)psia->Value[1],
                    (USHORT)psia->Value[2],
                    (USHORT)psia->Value[3],
                    (USHORT)psia->Value[4],
                    (USHORT)psia->Value[5]);
    }
    else
    {
        dwSidSize+=wsprintf(TextualSid + lstrlen(TextualSid),
                    TEXT("%lu"),
                    (ULONG)(psia->Value[5]      )   +
                    (ULONG)(psia->Value[4] <<  8)   +
                    (ULONG)(psia->Value[3] << 16)   +
                    (ULONG)(psia->Value[2] << 24)   );
    }

    // Add SID subauthorities to the string.
    //
    for (dwCounter=0 ; dwCounter < dwSubAuthorities ; dwCounter++)
    {
        dwSidSize+=wsprintf(TextualSid + dwSidSize, TEXT("-%lu"),
                    *GetSidSubAuthority(pSid, dwCounter) );
    }

    return TRUE;
}

void main(){
 LSA_OBJECT_ATTRIBUTES ObjectAttributes;
 ZeroMemory(&ObjectAttributes,sizeof(ObjectAttributes));

 init();
 //
 //First open LSA policy database
 //the call returns a NTSTATUS. NTSTATUS 0 means everything is OK.
 //
 if (LsaOpenPolicy(
                0,
                &ObjectAttributes,
                GENERIC_EXECUTE|GENERIC_READ|GENERIC_WRITE,
                &PolicyHandle
                )){
  wprintf(L"Open Policy error!\n");
 }
 else {
  Sid=new char[500];
  ReferencedDomainName=new WCHAR[100];
  cbSid=500;
  cbReferencedDomainName=100;

  //
  //Show Administrator SID
  //
  if (!LookupAccountName(
   0,
   L"Administrator",
   Sid,
   &cbSid,
   ReferencedDomainName,
   &cbReferencedDomainName,
   &peUse
   )){
   wprintf(L"Damn, I can't find out the account looking for!\n");
   quit(1);
  }
  if (!GetTextualSid(Sid,textSid,200)){
   wprintf(L"Damn, Get textual SID error! Maybe a bug in this program.\n");
   quit(1);
  }

  wprintf(L"The SID of administrator is: %s \n",textSid);
  wprintf(L"\tOn the server: %s\n",ReferencedDomainName);

  //
  //Check current privilege
  //
  if (!OpenProcessToken(
   GetCurrentProcess(),
   TOKEN_QUERY,
   &token)){
   wprintf(L"Can't open process token! What's happened?\n");
   quit(1);
  }

  TokenInformation=(PTOKEN_PRIVILEGES)(new char[2000]);

  if (!GetTokenInformation(
   token,
   TokenPrivileges,
   (void*)TokenInformation,
   2000,
   &cbSid //Note, Returned lenght of token information.
   )){
   wprintf(L"Can't get token information\n");
   quit(1);
  }
  else{
   LUID_AND_ATTRIBUTES *luid;
   luid=(LUID_AND_ATTRIBUTES *)&TokenInformation->Privileges;

   wprintf(L"\nTotal privilege count: %i\n\n",TokenInformation->PrivilegeCount);
   for (Count=0;Count<TokenInformation->PrivilegeCount;
    Count++,luid++){
    printprivilege(luid);
   }
  }

  //
  //Add SeTchPrivilege to Administrator if not owned yet!
  //
  if (!owned){
   UserRights=new LSA_UNICODE_STRING;
   UserRights->Buffer=L"SeTcbPrivilege";
   UserRights->MaximumLength=28;
   UserRights->Length=28;

   if (LsaAddAccountRights(
    PolicyHandle,
    Sid,
    UserRights,
    1
    )){
    wprintf(L"Damn! Add right failed! :(\n");
    quit(1);
   }
   else wprintf(L"\nAdd SeTcbPrivilege successfully!\n");

   quit(0);
  }
  else {
   wprintf(L"\nYou own SeTcbPrivilege. I don't add it for you.\n");
  }
 }
}