我最终想出了以下几点:
library mod_winimpersonate;
{$mode objfpc}{$H+}
uses SysUtils, Windows, httpd, apr, Classes;
function DefaultHandler(r: Prequest_rec): Integer; cdecl;
Var
cookies:TStringList;
logindata,username,password:String;
p:Integer;
begin
RevertToSelf;
cookies:=TStringList.Create;
cookies.Delimiter:=';';
cookies.DelimitedText:=apr_table_get(r^.headers_in,'COOKIE');
logindata:=URLDecode(cookies.Values['WinImpersonate']);
If Length(logindata)>0 then
Begin
p:=Pos(':',logindata);
username:=LeftStr(logindata,p-1);
password:=RightStr(logindata,Length(logindata)-p);
ChangeLoggedInUser(username,password,'');
End;
Result:=DECLINED;
end;
procedure RegisterHooks(p: Papr_pool_t); cdecl;
begin
ap_hook_handler(@DefaultHandler, nil, nil, APR_HOOK_REALLY_FIRST);
end;
var
TheModule: module;
exports TheModule name 'winimpersonate_module';
begin
FillChar(TheModule, sizeof(TheModule), 0);
STANDARD20_MODULE_STUFF(TheModule);
with TheModule do
begin
name := 'mod_winimpersonate.dll';
register_hooks := @RegisterHooks;
end;
end.
这绝不是最终的解决方案,但它是一个开始。逻辑如下:
恢复到 Apache 帐户。这是必须的,以防我们使用以前冒充其他人的回收 Apache 线程。
从名为“WinImpersonate”的 cookie 中检索用户的凭据,格式为username:password
. 这需要更多的工作(可能加密凭据,或者将它们存储在服务器上的安全(?)位置或更安全的地方)
在单位的帮助下冒充用户windows
。
Return DECLINED
,因此 Apache 知道我们没有处理请求,它应该继续向模块询问正确的处理程序。
有许多问题需要解决,以实现良好的安全级别。其中包括凭据保护和浏览器缓存。但正如我所说,这是一个开始,也是一个概念证明。
您会注意到上面的清单中缺少两个实用函数:
URLDecode
解码一个 url 编码的字符串:
// Convert URLEncoded string to utf8 string
function URLDecode(const s: String): String;
var
sAnsi: String;
sUtf8: String;
sWide: WideString;
i, len: Cardinal;
ESC: string[2];
CharCode: integer;
c: char;
begin
sAnsi := PChar(s);
SetLength(sUtf8, Length(sAnsi));
i := 1;
len := 1;
while (i <= Cardinal(Length(sAnsi))) do
begin
if (sAnsi[i] <> '%') then
begin
if (sAnsi[i] = '+') then c := ' ' else c := sAnsi[i];
sUtf8[len] := c;
Inc(len);
end
else
begin
Inc(i);
ESC := Copy(sAnsi, i, 2);
Inc(i, 1);
try
CharCode := StrToInt('$' + ESC);
c := Char(CharCode);
sUtf8[len] := c;
Inc(len);
except
end;
end;
Inc(i);
end;
Dec(len);
SetLength(sUtf8, len);
sWide := UTF8Decode(sUtf8);
len := Length(sWide);
Result := sWide;
end;
ChangeLoggedInUser
尝试使用提供的凭据登录用户,并在成功后尝试冒充他:
Function ChangeLoggedInUser(username, password, domain: string):Boolean;
var
creds: Cardinal;
begin
Result:=False;
try
if LogonUser(PChar(username)
,PChar(domain)
,PChar(password)
,LOGON32_LOGON_NETWORK_CLEARTEXT
,LOGON32_PROVIDER_DEFAULT
,creds
) then
begin
ImpersonateLoggedOnUser(creds);
Result:=True;
end;
finally
//wipe the memory for security
FillChar(username,SizeOf(username),#0);
FillChar(password,SizeOf(username),#0);
FillChar(domain,SizeOf(username),#0);
end; //try-finally
end;
希望有人觉得这很有用。非常欢迎评论。