转贴 Administrator用户直接获取SYSTEM权限

本文介绍了如何通过源代码实现Administrator用户直接获取SYSTEM权限的过程。作者首先展示了Gary Nebbett的方法,然后详细探讨了在2K/XP系统中遇到的问题及解决办法,包括权限不足的解决和代码调整。文章提供了两份源代码:sysproc.c和sysproc_now.c,分别演示了两种获取SYSTEM权限的实现。最后,作者提到这种方法需要注销并重新登录才能生效,因此在实际应用中失去了即时获取权限的价值。
摘要由CSDN通过智能技术生成
               

 Administrator用户直接获取SYSTEM权限


来源:http://www.nsfocus.com
作者:"scz" <scz@nsfocus.com>


标题: MSDN系列(3)--Administrator用户直接获取SYSTEM权限

日期: 2003-06-21 21:51
更新:

--------------------------------------------------------------------------

目录:

  ☆ 概述
  ☆ sysproc.c
  ☆ sysproc_now.c
  ☆ 参考资源

--------------------------------------------------------------------------

☆ 概述

翻看[5]的时候,其书中例8.1演示如何以SYSTEM身份启动cmd。以前我为了达到同样
目的,利用at命令,但平日里禁用Task Scheduler Service的,感觉操作很绕弯,不
爽得很。网上有现成的可执行程序直接获取SYSTEM权限,不喜欢没源码的此类型小工
具,从未试用过。

麻雀兄 <sparrow@smth>在水木清华MSDN版上共享了一份Ashot Oganesyan K的源代码,
也是直接获取SYSTEM权限。

一下子有了两份现成的短小精悍型源代码,心痒难耐,决定演练。最后发现还是麻雀
兄给的代码有实用价值。Gary Nebbett的代码对于2K/XP实际上失去了实用价值,这
要感谢rain的指点,具体技术讨论见后。

本文提供了两份完整源代码,sysproc.c、sysproc_now.c,前者演示Gary Nebbett的
办法,后者演示Ashot Oganesyan K的办法。

Ashot Oganesyan K的源代码只支持到2K,不清楚这位达人是否自己更新过,google
居然搜不到所提源代码(再次感谢sparrow共享),没办法,我只好自己增加了对XP和
2003 Server的支持。此外为方便使用,sysproc_now.c自己找出winlogon.exe的PID,
不必在命令行上指定拥有SYSTEM权限的PID了。

☆ sysproc.c

Gary Nebbett的中心思想就是利用ZwCreateToken()自己创建一个SYSTEM令牌(Token),
作为CreateProcessAsUser()第一形参使用。这个想法很好,我也费了好大劲去读令
牌相关的各类技术文档,可是到2K/XP环境中实测时却未达到预定效果。

开始完全按照Gary Nebbett所述编码,2K中ZwCreateToken()失败返回,说当前帐号
没有足够的权限。XP中说当前帐号不能指派为所伪造的SYSTEM令牌的所有者(Owner)。
关于这点参sysproc.c/CreateSystemToken()函数中的注释,从中也可看出XP比2K多
做了一些安全检查。后来统一使用sysproc.c中演示的方式,这下都成了权限不够的
错误提示。

知道调用ZwCreateToken()需要SE_CREATE_TOKEN_NAME权限,因此在程序中Enable了
该权限,当时相关的代码路径上并未提示Enable失败。因此对"权限不够"感到非常困
惑。鉴于我对Privilege理解不足,干脆不管三七二十一先将winnt.h中所列权限全部
Enable了,还是同样的下场。由此我才想到Administrator是否缺省并未被Grant某些
权限,AdjustTokenPrivileges()只能Enable/Disable那些已经Grant的权限,比如前
面所提的SE_DEBUG_NAME权限,并不能Grant权限。正好rain来北京,我们聚了两天,
顺带就此问题请教了rain和flier。rain为sysproc.c增加了一段代码,显示当前帐号
所拥有的权限,参CreateSystemToken()函数。从中发现Administrator果然没有所需
的SE_CREATE_TOKEN_NAME权限。rain告诉我,2K/XP中这种权限需要显式指派,也就
是"本地安全策略/用户权利指派"所做的事,NT是否需要显式指派我未证实过。缺省
情况下,CreateProcessAsUser()所需SE_ASSIGNPRIMARYTOKEN_NAME权限也未被指派
给管理员帐号。这两种权限在"本地安全策略/用户权利指派"中对应:

SE_CREATE_TOKEN_NAME     - Create a token object
SE_ASSIGNPRIMARYTOKEN_NAME - Replace a process level token

在此加深了对AdjustTokenPrivileges()的记忆。开始对MSDN中的描述并无感性认识,
只判断返回值为FALSE,而未判断GetLastError()为ERROR_NOT_ALL_ASSIGNED的情况,
导致当时相关的代码路径上并未提示Enable失败。

为管理员帐号手工增加这两种权限,注销并重新登录后,Gary Nebbett的目的达到了。

可以不利用"本地安全策略/用户权利指派",而是自己编程实现这个步骤([2])。利用
LsaOpenPolicy()、LsaAddAccountRights()即可,AddPrivilege()演示了这个过程。

但问题是无论如何都必须注销/重登录才会生效。这对我来说,事实上已经失去了利
用价值,我需要的是立即(now)获取SYSTEM权限。

可能有人由ZwCreateToken()联想到LogonUser(),关于后者可以参看[3]、[4],那不
是我需要的东西。

下面给出sysproc.c的完整源代码,秉承一贯风格,以不建工程(Solution/Project)
直接命令行编译为原则。注释相当冗长,那是写给我本人看的,对这些API特别不熟,
不写个注释在附近,下次看不懂是很正常的事,谁让该死的Windows API这么多形参。

--------------------------------------------------------------------------
/*
* For x86/EWindows XP SP1 & VC 7
* cl sysproc.c /Os /G6 /W3
*
* Gary Nebbett
* rain
*/

/************************************************************************
*                                               *
*                     Head File                     *
*                                               *
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <ntsecapi.h>

/************************************************************************
*                                               *
*                     Macro                       *
*                                               *
************************************************************************/

#pragma comment( linker, "/subsystem:console" )
#pragma comment( lib,   "advapi32.lib"     )

typedef LONG NTSTATUS;

/*
* you'll find a list of NTSTATUS status codes in the DDK header
* ntstatus.h (/WINDDK/2600.1106/inc/ddk/wxp/)
*/
#define NT_SUCCESS(status)       ((NTSTATUS)(status)>=0)
#define STATUS_SUCCESS         ((NTSTATUS)0x00000000L)

/*
*************************************************************************
* ntdef.h
*/

typedef struct _OBJECT_ATTRIBUTES
{
  ULONG       Length;
  HANDLE       RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG       Attributes;
  PVOID       SecurityDescriptor;
  PVOID       SecurityQualityOfService;
} OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;

/*
* ntdef.h
*************************************************************************
*/

/*
* 参看DDK文档以及<<Windows NT/2000 Native API Reference>> - Gary Nebbett
* 这些Native API由ntdll.dll输出
*/
typedef ULONG   ( __stdcall *RTLNTSTATUSTODOSERROR ) ( IN NTSTATUS Status );
typedef NTSTATUS ( __stdcall *ZWCREATETOKEN       ) ( OUT PHANDLE TokenHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN TOKEN_TYPE Type, IN PLUID AuthenticationId, IN PLARGE_INTEGER ExpirationTime, IN PTOKEN_USER User, IN PTOKEN_GROUPS Groups, IN PTOKEN_PRIVILEGES Privileges, IN PTOKEN_OWNER Owner, IN PTOKEN_PRIMARY_GROUP PrimaryGroup, IN PTOKEN_DEFAULT_DACL DefaultDacl, IN PTOKEN_SOURCE Source );

/************************************************************************
*                                               *
*                   Function Prototype                 *
*                                               *
************************************************************************/

static BOOL   AddCurrentProcessPrivilege
                    ( LPWSTR PrivilegeName );
static BOOL   AddPrivilege     ( LSA_HANDLE PolicyHandle,
                      PSID AccountSid, LPWSTR PrivilegeName );
static HANDLE CreateSystemToken ( void );
static BOOL   DisableCurrentProcessSomePrivilege
                    ( void );
static BOOL   EnableCurrentProcessSomePrivilege
                    ( void );
static PVOID GetFromToken     ( HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass );
static BOOL   LocateNtdllEntry ( void );
static void   PrintWin32Error   ( char *message, DWORD dwMessageId );
static void   PrintZwError     ( char *message, NTSTATUS status );
static BOOL   RemoveCurrentProcessPrivilege
                    ( LPWSTR PrivilegeName );
static BOOL   RemovePrivilege   ( LSA_HANDLE PolicyHandle,
                      PSID AccountSid, LPWSTR PrivilegeName );
static BOOL   SetCurrentProcessPrivilege
                    ( LPCTSTR PrivilegeName, BOOL EnableFlag );
static BOOL   SetPrivilege     ( HANDLE TokenHandle, LPCTSTR PrivilegeName,
                      BOOL EnableFlag );

/************************************************************************
*                                               *
*                   Static Global Var                 *
*                                               *
************************************************************************/

/*
* 由ntdll.dll输出的Native API函数指针
*/
static RTLNTSTATUSTODOSERROR RtlNtStatusToDosError = NULL;
static ZWCREATETOKEN       ZwCreateToken       = NULL;

/************************************************************************/

static BOOL AddCurrentProcessPrivilege ( LPWSTR PrivilegeName )
{
  NTSTATUS         status;
  BOOL             ret           = FALSE;
  LSA_HANDLE         PolicyHandle     = NULL;
  LSA_OBJECT_ATTRIBUTES ObjectAttributes;
  HANDLE           CurrentProcessToken = NULL;
  PTOKEN_USER       token_user       = NULL;

  ZeroMemory( &ObjectAttributes, sizeof( ObjectAttributes ) );
  /*
  * NTSTATUS LsaOpenPolicy
  * (
  *   PLSA_UNICODE_STRING   SystemName,
  *   PLSA_OBJECT_ATTRIBUTES ObjectAttributes,
  *   ACCESS_MASK         DesiredAccess,
  *   PLSA_HANDLE         PolicyHandle
  * );
  */
  status = LsaOpenPolicy( NULL, &ObjectAttributes, POLICY_ALL_ACCESS, &PolicyHandle );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaOpenPolicy() failed", LsaNtStatusToWinError( status ) );
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( FALSE == OpenProcessToken( GetCurrentProcess(),
                        TOKEN_QUERY,
                        &CurrentProcessToken ) )
  {
    PrintWin32Error( "OpenProcessToken() failed", GetLastError() );
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( NULL == ( token_user = ( PTOKEN_USER )GetFromToken( CurrentProcessToken, TokenUser ) ) )
  {
    goto AddCurrentProcessPrivilege_exit;
  }
  if ( FALSE == AddPrivilege( PolicyHandle,
                    token_user->User.Sid,
                    PrivilegeName ) )
  {
    goto AddCurrentProcessPrivilege_exit;
  }
  ret   = TRUE;

AddCurrentProcessPrivilege_exit:

  if ( NULL != token_user )
  {
    free( token_user );
    token_user = NULL;
  }
  if ( NULL != CurrentProcessToken )
  {
    CloseHandle( CurrentProcessToken );
    CurrentProcessToken = NULL;
  }
  if ( NULL != PolicyHandle )
  {
    LsaClose( PolicyHandle );
    PolicyHandle = NULL;
  }
  return( ret );
} /* end of AddCurrentProcessPrivilege */

/*
* 留心第二形参是宽字符串
*/
static BOOL AddPrivilege ( LSA_HANDLE PolicyHandle, PSID AccountSid, LPWSTR PrivilegeName )
{
  BOOL           ret = FALSE;
  LSA_UNICODE_STRING UserRights;
  USHORT         StringLength;
  NTSTATUS       status;

  if ( PrivilegeName == NULL )
  {
    goto AddPrivilege_exit;
  }
  StringLength         = wcslen( PrivilegeName );
  UserRights.Buffer     = PrivilegeName;
  UserRights.Length     = StringLength * sizeof( WCHAR );
  UserRights.MaximumLength = ( StringLength + 1 ) * sizeof( WCHAR );
  /*
  * Header : Declared in Ntsecapi.h.
  * Library: Use Advapi32.lib.
  *
  * NTSTATUS LsaAddAccountRights
  * (
  *   LSA_HANDLE       PolicyHandle,
  *   PSID           AccountSid,
  *   PLSA_UNICODE_STRING UserRights,
  *   ULONG           CountOfRights
  * );
  */
  status             = LsaAddAccountRights( PolicyHandle, AccountSid, &UserRights, 1 );
  if ( status != STATUS_SUCCESS )
  {
    PrintWin32Error( "LsaAddAccountRights() failed", LsaNtStatusToWinError( status ) );
    goto AddPrivilege_exit;
  }
  ret               = TRUE;

AddPrivilege_exit:

  return( ret );
} /* end of AddPrivilege */

static HANDLE CreateSystemToken ( void )
{
  NTSTATUS             status;
  HANDLE               CurrentProcessToken       = NULL;
  HANDLE               SystemToken           = NULL;
  SID_IDENTIFIER_AUTHORITY   sid_identifier_authority   = SECURITY_NT_AUTHORITY;
  PTOKEN_PRIVILEGES       token_privileges         = NULL;
  /*
  * typedef struct _TOKEN_USER
  * {
  *   SID_AND_ATTRIBUTES User;
  * } TOKEN_USER, *PTOKEN_USER;
  *
  * typedef struct _SID_AND_ATTRIBUTES
  * {
  *   PSID Sid;
  *   DWORD Attributes;
  * } SID_AND_ATTRIBUTES, *PSID_AND_ATTRIBUTES;
  */
  TOKEN_USER             token_user             = { { NULL, 0 } };
  /*
  * typedef struct _TOKEN_SOURCE
  * {
  *   Char SourceName[8];
  *   LUID SourceIdentifier;
  * } TOKEN_SOURCE, *PTOKEN_SOURCE;
  *
  * typedef struct _LUID
  * {
  *   D

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值