2007 11 Spoofing i Sniffing w Pythonie

background image

www.hakin9.org

hakin9 Nr 11/2007

30

Atak

O

becnie eksperci zajmujący się bez-
pieczeństwem komputerowym mo-
gą korzystać z całej gamy aplikacji

służących do analizy ruchu w sieci, pisania
exploitów, skanowania portów czy wykrywa-
nia włamań. Niektóre z tych programów ma-
ją już ugruntowaną pozycję i korzystanie z
nich stało się pewnym standardem. Bywa
jednak, że niektóre ze znanych narzędzi nie
spełniają wszystkich naszych wymagań lub
z pewnych przyczyn nie możemy z nich sko-
rzystać. Wtedy z pomocą przychodzi język
Python i nasza kreatywność – w kilka chwil
możemy napisać skrypt, który będzie dosto-
sowany do konkretnego problemu i, co naj-
ważniejsze, jego budowa będzie nam do-
brze znana.

Dlaczego Python?

Jest kilka powodów, dla których warto rozpo-
cząć naukę tego języka. Po pierwsze, jest to
język, który stale się rozwija i jest ciągle udo-
skonalany. Wydany jest na licencji Open So-
urce
, zapewniającej stałe wsparcie rzeszy
oddanych programistów. Co więcej, Python
jest językiem łatwym w nauce, a jego kod jest
bardzo przejrzysty. Pozwala to na łatwą mo-

dyfikację źródła aplikacji, nawet przez oso-
by niebędące znawcami tego języka. Jednak
największym plusem jest ogromna ilość mo-
dułów i frameworków rozszerzających możli-
wości języka. Dotyczą one zarówno progra-
mowania sieciowego, interfejsów graficznych
jak i np. obróbki grafiki.

Idealnym przykładem jest moduł Inline-

Egg, który został już opisany na łamach ha-
kin9. Kolejnymi, doskonałymi przykładami,
mogą być rozszerzenia przybliżane w tym

Spoofing i Sniffing

w Pythonie

Piotr Łaskawiec

stopień trudności

Każdy specjalista ds. bezpieczeństwa komputerowego powinien

być w stanie pisać programy pomagające w audycie lub analizie

ewentualnych zagrożeń. Programy te powinny być proste,

przejrzyste i co najważniejsze, ich budowa powinna zajmować

mało czasu. Programy pisane w Pythonie spełniają wszystkie

powyższe warunki.

Z artykułu dowiesz się

• jak pisać aplikacje sieciowe w języku Python,
• jak szybko przechwytywać i odczytywać pakie-

ty w Sieci,

• czym jest spoofing i jak można napisać pro-

gram modyfikujący pakiety w Pythonie.

Co powinieneś wiedzieć

• powinieneś znać podstawy działania sieci

TCP/IP,

• powinieneś znać podstawy Pythona.

background image

Aplikacje sieciowe w Pythonie

hakin9 Nr 11/2007

www.hakin9.org

31

artykule, czyli Pcapy i Impacket.
Wszystkie programy napisane na
potrzeby tej publikacji były testo-
wane na systemie operacyjnym Li-
nux, z zainstalowanym Pythonem
w wersji 2.5 (którego można po-
brać ze strony (1)).

Moduł Socket

Python posiada duży zbiór stan-
dardowych modułów służących do
programowania sieciowego. Ideą
Pythona jest udostępnienie wszyst-
kich najpotrzebniejszych narzę-
dzi wraz z pakietem instalacyjnym.

Moduł socket daje nam swobodny
dostęp do gniazd (sockets), czyli
abstrakcyjnych obiektów pozwala-
jących nam na nawiązywanie połą-
czeń, transmisję danych itd.

Funkcja

socket([rodzina _ adresu[,

typ _ gniazda[, numer _ protokolu]]])

odpowiedzialna jest za tworzenie
nowego gniazda. W Ramce przed-
stawione są możliwe typy gniazd
i rodziny adresów wraz ze sto-
sownym opisem. Do gniazda przy-
porządkowane są także niezbęd-
ne funkcje, odpowiadające opera-
cjom które może wykonywać soc-
ket:

listen()

– oczekiwanie na połą-

czenia dla danego gniazda,

accept()

– akceptacja oczekują-

cego połączenia,

bind()

– przypisanie adresu do

gniazda,

connect()

– nawiązanie połącze-

nia,

close()

– zamknięcie połączenia

i anulowanie wszystkich operacji.

Listingi 1 i 2 obrazują łatwość pisa-
nia programów w Pythonie. W kilka
minut można napisać prostą aplika-
cję typu klient-serwer. Kod pokaza-
ny na Listingach jest bardzo pro-
sty i tym samym jest dobrym wpro-
wadzeniem do dalszej części arty-
kułu.

Pcapy i Impacket

Są to dwa moduły usprawniające
programowanie sieciowe w Pytho-
nie. Pcapy pozwala na wyłapywa-
nie pakietów z sieci, natomiast Im-
packet
służy do ich szczegółowej
analizy i modyfikacji. Obsługuje on
zarówno protokoły niskopoziomowe
(IP, TCP, UDP, ICMP), jak i proto-
koły wysokiego poziomu. Oba mo-
duły idealnie ze sobą współpracu-
ją. Można je pobrać ze strony (2).
W celu instalacji obu modułów,
przechodzimy do katalogu ze źró-
dłem i wydajemy polecenie:

python setup.py install

Należy także pamiętać, że do po-
prawnego działania Pcapy potrzeb-

Rodziny adresów

AF_UNIX

– Gniazdo uniksowe, zapewniające wydajną komunikację międzyproceso-

wą na tej samej maszynie. W Pythonie adresy tych gniazd reprezentowane są w po-
staci łańcuchów.

AF _ INET

– Gniazdo zapewniające komunikację na dwóch różnych maszynach

przy wykorzystaniu adresowania IPv4. Reprezentowane jest przez układ (

host

,

port

), gdzie

host

jest łańcuchem znaków a

port

liczbą całkowitą.

AF _ INET6

– Gniazdo różni się od

AF _ INET

tylko zmianą adresowania z IPv4 na

IPv6. Obecnie jest ono bardzo rzadko używane.

Typy gniazd

SOCK_STREAM

– odpowiada za komunikację połączeniową,

SOCK _ DGRAM

– odpowiada za komunikację bezpołączeniową,

SOCK _ RAW

– zapewnia dostęp do warstw położonych poniżej warstwy aplikacyj-

nej. Pozwala na manipulację surowymi pakietami na poziomie warstwy sieciowej,

SOCK _ RDM

– gniazdo komunikatów niezawodnie doręczanych,

SOCK _ SEQPACKET

– gniazdo pakietów uporządkowanych.

Rysunek 1.

Działanie sniffera

W Sieci

http://www.python.org – strona domowa Pythona (1),
http://www.oss.coresecurity.com/ – strona domowa modułów pcapy i impacket (2),
http://www.tcpdump.org – strona projektu libpcap (3),
http://www.twistedmatrix.com – strona projektu Twisted (4).

background image

hakin9 Nr 11/2007

www.hakin9.org

Atak

32

ny jest Libcap w wersji 0.9.3 lub now-
szej. Można go pobrać ze strony (3).

Inne rozwiązania

Szybki wzrost popularności Py-
thona powoduje ciągłe powstawa-
nie nowych rozwiązań programi-
stycznych. Jednym z nich jest Twi-
sted
– alternatywa dla omawianych
w tym artykule modułów Pcapy
i Impacket. Twisted jest framewor-
kiem, który dostarcza nam wielu
mechanizmów pomagających w pi-
saniu aplikacji sieciowych. Zapew-
nia on wsparcie takich protokołów
jak TCP, UDP, SSL/TLS, HTTP,
SSH itd. Z Twisted korzysta wie-
le znanych programów, m. in. Bit-
Torrent oraz Zope3. Twisted moż-
na pobrać ze strony (4). Instalacja
przebiega analogicznie, jak w przy-
padku Pcapy i Impacket. Wchodzi-
my do katalogu, w którym umiesz-
czone są źródła i wydajemy polece-
nie python setup.py install. Gorąco
polecam zaznajomienie się z tym
projektem w wolnej chwili.

Piszemy sniffer

Pierwszym przydatnym programem
który napiszemy, będzie sniffer. Za-
danie stawiane przed naszą apli-
kacją jest oczywiste – ma on prze-
chwytywać pakiety i wyświetlać ich
zawartość. Program ten stanowi
świetne narzędzie diagnostyczne
i jest nieoceniony w pewnych sytu-
acjach, dlatego uważam, że war-
to poznać jego budowę. Przeana-
lizujmy kod zamieszczony w Listin-
gu 3. Źródło składa się z kilkunastu
linijek i stanowi w pełni działający
sniffer. Program wykorzystuje tzw.
surowe gniazda (raw sockets) oraz
dwa moduły: moduł socket, któ-
ry jest standardowym składnikiem
Pythona, a także moduł Impacket.
W kodzie na Listingu 3. należy zwró-
cić uwagę na sposób tworzenia
obiektu socket. Do funkcji

socket()

przekazywane są 3 argumenty:

AF _ INET, SOCK _ RAW

i numer proto-

kołu. Numer protokołu jest elemen-
tem wymaganym podczas manipu-
lowania surowymi gniazdami. Nu-
mer ten możemy pozyskać za po-
mocą funkcji

getprotobyname()

, któ-

Listing 1.

Prosty serwer

import

socket

#tworzymy gniazdo

mysocket

=

socket

.

socket

(

socket

.

AF_INET

,

socket

.

SOCK_STREAM

)

#laczymy gniazdo z odpowienim portem

mysocket

.

bind

((

''

,

1234

))

mysocket

.

listen

(

5

)

while

True

:

#Akceptacja polaczenia

client

,

address

=

mysocket

.

accept

()

print

'Nowe polaczenie: '

,

address

# Wysylamy banner do klienta

client

.

send

(

'Witamy na testowym serwerze'

)

#Zamykamy polaczenie

client

.

close

()

Listing 2.

Prosty klient

import

socket

#tworzymy gniazdo

mysocket

=

socket

.

socket

(

socket

.

AF_INET

,

socket

.

SOCK_STREAM

)

#nawiazujemy polaczenie

mysocket

.

connect

((

'localhost'

,

1234

))

#odbior i drukowanie danych

temp

=

mysocket

.

recv

(

1024

)

print

temp

#zamykamy polaczenie

mysocket

.

close

()

Listing 3.

Sniffer-Impacket

import

socket

from

impacket

import

ImpactDecoder

#wykorzystywany protokol

protocol

=

"tcp"

#zamiana nazwy protokolu na liczbe

int_protocol

=

socket

.

getprotobyname

(

protocol

)

#tworzymy surowe gniazdo

mysocket

=

socket

.

socket

(

socket

.

AF_INET

,

socket

.

SOCK_RAW

,

int_protocol

)

mysocket

.

setsockopt

(

socket

.

IPPROTO_IP

,

socket

.

IP_HDRINCL

,

1

)

print

"Nasluchuje..."

#tworzymy dekoder

ipdecoder

=

ImpactDecoder

.

IPDecoder

()

while

True

:

#odbieranie danych

packet

=

mysocket

.

recvfrom

(

4096

)[

0

]

if

0

==

len

(

packet

):

mysocket

.

close

()

break

;

else

:

#dekodowanie danych

packet

=

ipdecoder

.

decode

(

packet

)

print

packet

background image

Aplikacje sieciowe w Pythonie

hakin9 Nr 11/2007

www.hakin9.org

33

ra zwraca nam odpowiednią liczbę
na podstawie nazwy protokołu. Ko-
lejną ważną i często używaną funk-
cją jest

setsockopt()

, która służy do

ustawiania opcji gniazda. W na-
szym przypadku ustawiamy para-
metr

IP _ HDRINCL

na wartość

True

.

Jest on odpowiedzialny za dostar-
czenie aplikacji nagłówków pakie-
tu. Opcja ta może występować tyl-
ko wtedy, gdy korzystamy z suro-
wych gniazd.

W kodzie przedstawionym na

Listingu 3. kluczową rolę odgrywa
obiekt

ipdecoder

. Jest on tworzony

poprzez

ipdecoder = ImpactDecoder

.IPDecoder()

i służy do konwersji su-

rowych pakietów na jednostki zrozu-
miałe dla modułu Impacket. Umożli-

wia to swobodną manipulację pakie-
tami i wyświetlenie pakietu w spo-
sób przejrzysty. Sam proces deko-
dowania odbywa się poprzez funkcję

decode()

, do której przekazujemy po-

brane dane.

Wykorzystanie modułu socket

nie jest jedyną drogą prowadzą-
cą do napisania sniffera. Możemy
również wykorzystać moduł Pcapy.
Kod programu, który opiera się na
Pcapy i Impacket, przedstawiony
jest na Listingu 4. Niewątpliwą za-
letą takiego rozwiązania jest moż-
liwość wykorzystania kilku przy-
datnych funkcji będących częścią
Pcapy.

Pierwszą rzeczą, na którą warto

zwrócić uwagę, jest funkcja

findall-

devs()

. Zwraca ona listę wszystkich

aktywnych interfejsów sieciowych.
Umożliwia to łatwy wybór źródła
pakietów i nie ogranicza nas do do-
myślnego interfejsu.

Kolejne ułatwienie przychodzi

wraz z funkcją

setfilter()

. Umożli-

wia ona dostosowywania naszego
sniffera do konkretnego protokołu.
Oprócz TCP, który został wykorzy-
stany w naszym przykładzie, może-
my także skorzystać z innych zna-
nych protokołów (np. ICMP).

Sercem programu jest funkcja

open _ live()

. Służy ona do otwie-

rania konkretnego urządzenia w ce-
lu wyłapania pakietów. Przekazuje-
my do niej nazwę urządzenia, ilość
pobieranych bajtów, flagę trybu pro-
miscuous i opóźnienie. Działający
sniffer przedstawia Rysunek 1.

Piszemy spoofer

Czas na napisanie innego, równie
przydatnego programu. Na Listingu
5. został zamieszczony kod proste-
go spoofera napisanego w Pythonie
przy użyciu modułów socket i Impac-
ket
. W czasie pisania programu zo-
stały wykorzystane sposoby progra-
mowania opisane przy okazji wcze-
śniejszych przykładów. Sam pro-
gram spełnia kilka ważnych warun-
ków:

• kod jest krótki, przejrzysty i opty-

malny,

• program potrafi modyfikować ad-

res nadawcy i port,

• program potrafi zmieniać usta-

wienia flag SYN i ACK,

spoofer potrafi zmieniać wartość

TTL (time-to-live).

Dzięki aplikacji z Listingu 5. jesteśmy
w stanie wysłać własnoręcznie zmo-
dyfikowany pakiet na dowolny adres
w sieci. Jest to przydatne przy pew-
nych rodzajach ataków, o których na-
piszę później. Nasz spoofer urucha-
miamy poprzez wywołanie z konso-
li komendy:

python sniff.py<adres_odbiorcy>
<port_odbiorcy><adres_nadawcy>
<port_nadawcy><wart_SYN>
<wart_ACK><wart_TTL>

Terminologia

Sniffing – jest to monitorowanie komunikacji między urządzeniami w sieci. Snif-

fery pasywnie przechwytują pakiety komunikacji sieciowej serwera, routera czy
bramy. Podstawą działania sniffera jest tworzenie kopii informacji wysyłanych
i odbieranych przez urządzenie sieciowe. Wśród tych informacji można zna-
leźć wiele przydatnych danych, które mogą być pomocne w analizie architektu-
ry sieci lub podczas opracowywania odpowiedniego wektora ataku. Należy jed-
nak pamiętać, że sniffing jest możliwy tylko wtedy, gdy pakiety docierają do na-
szych interfejsów sieciowych.

Spoofing – jest to podrabianie adresów IP i nazw DNS w celu uzyskania autoryza-

cji i możliwości komunikacji z chronioną stacją docelową. Spoofing polega głównie
na przechwyceniu i modyfikacji pakietów przesyłanych między dwoma urządzenia-
mi lub przekierowaniu pakietów ze stacji docelowej do atakującego.

Tryb promiscuous

Jest to tryb pracy karty sieciowej (lub innego, dowolnego interfejsu sieciowego), w któ-
rym przechwytuje ona wszystkie pakiety krążące w sieci, a nie tylko te adresowane
bezpośrednio do niej (poprzez adres MAC). Pozwala to na podsłuchiwanie ruchu w ra-
mach swojego segmentu Sieci.

Raw Sockets

Raw sockets są rodzajem gniazd sieciowych, które zapewniają dostęp do nagłów-
ków pakietów wysyłanych i pobieranych z sieci. W przypadku korzystania z raw soc-
kets, programista otrzymuje pełną kontrolę nad procesem tworzenia pakietu i co za
tym idzie, odpowiada za jego poprawne oznakowanie i zaadresowanie. Surowe gniaz-
da pozwalają także na dostęp do warstw leżących poniżej warstwy aplikacji w mode-
lu OSI, a więc do warstwy transportowej i warstwy sieciowej. Zwiększa to nasze moż-
liwości i oferuje praktycznie nieograniczone sposoby na modyfikację wysyłanych i od-
bieranych pakietów.

background image

hakin9 Nr 11/2007

www.hakin9.org

Atak

34

Przeanalizujmy teraz kod progra-
mu. Po zaimportowaniu odpowied-
nich modułów następuje przypisa-
nie zmiennym wartości podanych
przez użytkownika oraz deklara-
cja protokołu (w naszym przypadku
jest to TCP). Korzystamy z surowych
gniazd, więc konieczne będzie obli-
czenie wartości liczbowej odpowia-
dającej protokołowi TCP. Następ-
nie tworzymy obiekt IP poprzez mo-
duł impacket. Instancja klasy IP jest
implementacją protokołu IP działają-
cego w warstwie sieciowej modelu
OSI. Zgodnie z tym uzupełniamy da-
ne potrzebne do prawidłowego zbu-
dowania nagłówka – adres nadawcy
i odbiorcy, a także wartość TTL. Do-
konujemy tego za pomocą funkcji:

set_ip_src(), set_ip_dst()

oraz

set_ip_ttl().

Analogicznie postępujemy z obiek-
tem reprezentującym protokół TCP.
Aby uzupełnić braki w nagłówku
TCP (port źródłowy, port docelowy,
wartości SYN i ACK), posługujemy
się funkcjami:

set_th_sport(), set_th_dport(),

set_th_seq()

i

set_th_ack().

Ostatnią rzeczą o jakiej musimy pa-
miętać, jest wygenerowanie sumy
kontrolnej. Suma kontrola (check-
sum
) jest częścią nagłówka pakietu
TCP i jest wymagana do ustanowie-
nia połączenia:

tcp.calculate_checksum()
tcp.auto_checksum = 1

Ustawienie atrybutu

auto _ checksum

na wartość 1 (równoznaczne z

True

)

informuje program, że suma kontro-
lna będzie wygenerowana automa-
tycznie dla każdego kolejnego pa-
kietu. Zmiana tego atrybutu na 0
wymusi na nas ręczne podawanie

Listing 4.

Sniffer-Pcapy, Impacket

import

pcapy

from

impacket

import

ImpactDecoder

def

packet_recive

(

handler

,

data

):

#dekodowanie danych

decoded

=

ImpactDecoder

.

EthDecoder

()

.

decode

(

data

)

print

decoded

#listujemy interfejsy sieciowe

eths

=

pcapy

.

findalldevs

()

print

"Interfejsy sieciowe: "

i

=

0

for

eth

in

eths

:

print

"%d: %s"

%

(

i

,

eths

[

i

])

i

+=

1

choose

=

int

(

raw_input

(

"Wybierz interfejs: "

))

eth

=

eths

[

choose

]

#

source

=

pcapy

.

open_live

(

eth

,

1500

,

1

,

100

)

source

.

setfilter

(

'tcp'

)

print

"Siec:%s Maska:%s

\n

"

%

(

source

.

getnet

()

,

source

.

getmask

())

#reakcja na przychodzące pakiety

source

.

loop

(-

1

,

packet_recive

)

Listing 5.

Spoofer

import

socket

import

sys

from

impacket

import

ImpactPacket

protocol

=

"tcp"

int_protocol

=

socket

.

getprotobyname

(

protocol

)

dst_host

=

sys

.

argv

[

1

]

dst_port

=

int

(

sys

.

argv

[

2

])

src_host

=

sys

.

argv

[

3

]

src_port

=

int

(

sys

.

argv

[

4

])

SYN

=

int

(

sys

.

argv

[

5

])

ACK

=

int

(

sys

.

argv

[

6

])

TTL

=

int

(

sys

.

argv

[

7

])

#tworzymy obiekt IP

ip

=

ImpactPacket

.

IP

()

#deklarujemy adresata, odbiorce i wartosc TTL

ip

.

set_ip_src

(

src_host

)

ip

.

set_ip_dst

(

dst_host

)

ip

.

set_ip_ttl

(

TTL

)

#tworzymy obiekt TCP

tcp

=

ImpactPacket

.

TCP

()

tcp

.

set_th_sport

(

src_port

)

#deklarujemy port zrodlowy, port docelowy, wartosci SYN i ACK

tcp

.

set_th_dport

(

dst_port

)

tcp

.

set_th_seq

(

SYN

)

tcp

.

set_SYN

()

tcp

.

set_th_ack

(

ACK

)

tcp

.

set_ACK

()

ip

.

contains

(

tcp

)

#obliczamy sume kontrolna

tcp

.

calculate_checksum

()

tcp

.

auto_checksum

=

1

#nawiazujemy polaczenie i wysylamy pakiet

mysocket

=

socket

.

socket

(

socket

.

AF_INET

,

socket

.

SOCK_RAW

,

int_protocol

)

mysocket

.

setblocking

(

0

)

mysocket

.

setsockopt

(

socket

.

IPPROTO_IP

,

socket

.

IP_HDRINCL

,

1

)

mysocket

.

sendto

(

ip

.

get_packet

()

,

(

dst_host

,

dst_port

))

background image

sumy kontrolnej (co w niektórych przypadkach jest sytu-
acją pożądaną).

Ciekawą i na pewno godną zapamiętania funkcją

jest

setblocking()

. Gdy przekażemy do funkcji 0, gniaz-

do nie będzie blokowane. Oznacza to, że każde nie-
udane wysłanie pakietu danych lub brak możliwości
odebrania takiego pakietu z sieci spowodują wywoła-
nie wyjątku.

Należy teraz zastanowić się nad praktycznym za-

stosowaniem takiego programu. Istnieje wiele ataków,
u podstaw których leży modyfikacja wysyłanych pakie-
tów. Jednym z takich ataków jest atak typu SYN. Do ata-
kowanego komputera wysyłane jest żądanie połącze-
nia TCP (SYN). Wysyłane pakiety mają zmieniony ad-
res nadawcy (na adres innego komputera w sieci). Wy-
słanie odpowiednio dużej ilości takich pakietów powo-
duje zaangażowanie bardzo dużych zasobów na atako-
wanej maszynie.

W wyniku tego możemy doprowadzić do zawiesze-

nia atakowanej maszyny. Kolejnym atakiem wykorzy-
stującym spoofing jest DNS Amplification. Polega on
na wysłaniu zapytań do serwerów DNS ze zmodyfi-
kowanym adresem zwrotnym (adres zwrotny ustawia-
ny jest na adres atakowanej maszyny). Przy wykorzy-
staniu większej ilości komputerów wysyłających zapy-
tanie, komputer ofiary nie jest w stanie obsłużyć połą-
czeń kierowanych z serwerów DNS i najczęściej zawie-
sza się. Jak widać, spoofing ma swoje zastosowanie
w praktyce.

Podsumowanie

Umiejętność pisania aplikacji sieciowych w Pythonie jest
cenna. Pozwala nam szybko i przyjemnie pisać aplikacje
dostosowane do konkretnego przypadku. Łatwość pisa-
nia gwarantuje nam duży komfort pracy, a duże możliwo-
ści samego języka i jego modułów pozwalają na stworze-
nie praktycznie dowolnego programu.

W tym artykule zostały przedstawione podstawy pro-

gramowania sieciowego. Jest to pewna fundamentalna
wiedza, która przy odrobinie chęci i samozaparcia po-
zwala pisać bardziej złożone aplikacje. W dzisiejszych
czasach umiejętność pisania programów mających prak-
tyczne zastosowanie w procesie audytu jest na wagę zło-
ta. Równie ważny jest czas poświęcony na kodowanie.
Pamiętajmy więc, że Python jest językiem, który ideal-
nie łączy szybkość pracy z instynktownym programowa-
niem. l

O autorze

Piotr Łaskawiec od wielu lat związany z tematyką bezpie-
czeństwa komputerowego. Pasjonat języka Python. Założy-
ciel i przewodniczący Koła Naukowego PK IT Security Gro-
up (www.pkitsec.pl). W wolnych chwilach programuje i zajmu-
je się publicystyką.
Kontakt z autorem: hellsource@gmail.com


Wyszukiwarka

Podobne podstrony:
kurier lubelski magazyn 2007 11 09 romans w pracy pdf
2007 11 21 1353 sprostowanie
EDW 2007 11
giełda na koła, oddechowka2, Wysłany: Wto 16 Sty, 2007 11:20 FIZJOLOGIA - giełda ODDECHÓWKA
biologia geol 2007 11 29 wyklad2 bez ilustr
2007-11-08 Reprywatyzacja odblokowana, materiały, Z PRASY
e projekt 2007 11 Rys 6
2007 11 Szkola konstruktorowid Nieznany
biologia geol 2007 11 22 wyklad1 bez ilustr
Wykład 3 2007-11-05 Oscyloskopy
2007 11 UML – modelowanie dynamicznych aspektów oprogramowania [Inzynieria Oprogramowania]
e projekt 2007 11 Rys 2
2007-11-06 Deweloperzy oczekują zmiany przepisów, materiały, Z PRASY
Wykłady Maćkiewicza, 2007.11.07 Językoznawstwo ogólne - wykład 4, Językoznawstwo ogólne
Wykład 3 2007-11-05 Oscyloskopy

więcej podobnych podstron