Προς το περιεχόμενο

Fork bombs και άλλα τέρατα


Ozone

Προτεινόμενες αναρτήσεις

Τρίτη «υπόδειξη»: ακόμα και να τα κάνεις kill -9 όλα, η kill() syscall παίρνει ένα argument, το οποίο σημαίνει ότι τι shell θα πάει να τα εκτελέσει ένα-ένα και για καθένα που θα σκοτώνεις, θα ξεπηδάει ένα άλλο απ' τη γωνία.

 

Πρέπει να γίνει σε 2 στάδια νομίζω: Πρώτα στέλνεις SIGSTOP στις processes και μετά αρχίζεις να τους παίρνεις το scalp.

 

Δεν έχω πρόσβαση αυτήν τη στιγμή σε unix-οειδές για να τεστάρω και να δώσω μία ολοκληρωμένη υλοποίηση. Sorry! :rolleyes:

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

  • Απαντ. 85
  • Δημ.
  • Τελ. απάντηση

Ωραίος ο parsifal! Οπότε περνάμε στο

 

Μάθημα 1ο: Σήματα (signals)

 

Τα σήματα είναι ένας βασικός τρόπος ενδοεπικοινωνίας μεταξύ των διεργασιών σε ένα POSIX σύστημα. Ουσιαστικά πρόκειται για καποια boolean κανάλια, τα οποία μπορεί να χρησιμοποιήσει ένα process για να πει σε ένα άλλο να κάνει κάτι.

 

Τα σήματα δεν είναι τίποτα άλλο παρά αριθμοί, οι οποίοι μεταφράζονται κατάλληλα από το λειτουργικό ή/και τη διεργασία προς την οποία απευθύνονται. π.χ. το SIGTERM, που είναι αυτό που στέλνει η kill από μόνη της, έχει την τιμή 15, ενώ το SIGKILL την τιμή 9 (εξ ου και το kill -9). Τα σήματα στέλνονται με τη βοήθεια της κλήσης συστήματος (system call) kill(2), η οποία λαμβάνει τη μορφή kill(pid, signal).

 

Κάθε διεργασία μπορεί να κάνει register έναν ή περισσότερους signal handlers, δηλαδή κομμάτια κωδικα που εκτελούνται όταν λάβει συγκεκριμένα σήματα. Μπορεί επίσης να επιλέξει να μην αντιδρά καθόλου σε ένα σήμα (ignore). Έτσι, συνήθως οι μεγάλες εφαρμογές κάνουν register signal handler για το SIGTERM, ώστε όταν κάποιος τους ζητήσει να κλείσουν, να το κάνουν «συμμαζεύοντας» τυχόν δεδομένα που εχουν στη μνήμη, ανοιχτά αρχεία/συνδέσεις, κλπ. Το SIGTERM όμως, μπορούν και να το κάνουν ignore, οποτε ένα απλό kill αδυνατεί να σκοτώσει μια τέτοια διεργασία. Εκτός από το SIGTERM, οι εφαρμογές πολλές φορές χρησιμοποιούν το SIGHUP (hangup) για να ξαναδιαβάσουν τα αρχεία ρυθμισεών τους και τα SIGUSR1 και SIGUSR2 για custom ενέργειες (που συνήθως αναγράφονται στη manpage της εφαρμογής).

 

Υπάρχουν ωστόσο δύο ενδιαφέρουσες περιπτώσεις σημάτων, το SIGSTOP και το SIGKILL. Τα δύο αυτά σήματα έχουν ένα κοινό: δεν μπορούν να αγνοηθούν, ούτε να αντιστοιχιστούν σε signal handlers, οπότε έχουν πάντα μια σαφώς καθορισμένη συμπεριφορά:

  • Το SIGSTOP «παγώνει» τη διεργασία στην τρέχουσα κατάσταση εκτέλεσης, σαν κάποιος να πάτησε pause (ουσιαστικά ο scheduler σταματάει να δίνει στο process cpu cycles).
  • To SIGKILL σκοτώνει επιτόπου τη διεργασια, άμεσα.

 

Όπως είπαμε, η συγκεκριμένη fork bomb προσπαθεί διαρκώς (endless loop) να κάνει fork(). Οταν εξαντληθεί το process space, η fork() αποτυγχάνει, όμως η διεργασία συνεχίζει. Επειδή ήδη εχει αρκετα children, για κάθε διεργασία που σκοτώνεται σίγουρα κάποιο fork() θα επιτυγχανει σχεδόν ακαριαία, με αποτέλεσμα να ξαναγεμίζει το process table.

 

Επομένως, πρέπει κάπως να αδρανοποιήσουμε τα processes της forkbomb (με το SIGSTOP προφανώς) και μετά να τα σκοτώσουμε ένα-ένα (με SIGKILL). Εφόσον όλες οι βόμβες είναι STOPPED (Τ state στο top/ps), τότε θα αδειάσουν ένα-ένα τα slots του process table που καταλαμβάνουν, μέχρι το τελευταίο.

 

Περνάμε λοιπόν στο επόμενο στάδιο: πως θα αναγνωρίσουμε ποια PIDs ανήκουν στη fork bomb, ειδικά όταν δεν έχουμε τη δυνατότητα να χρησιμοποιήσουμε τίποτα άλλο εκτός από το shell που έχουμε διαθέσιμο εκείνη τη στιγμή; Επόμενα στο 2ο μάθημα, με τίτλο "procfs".

 

Βιβλιογραφία:

manpages για signal(7), signal(2), sigaction(2), kill(1) και kill(2)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Όντως!

 

Αλλά τα PID πώς είπαμε ότι τα βρίσκουμε; Ειδικά αφού δεν υπάρχει τρόπος να διαβάσουμε από το shell τις πλρηροφορίες κάθε process από το /proc/<PID>/* χωρίς εξωτερικές εντολές (ή υπάρχει; ). Εκτός αν αλλάζαμε shell (με exec) σε irb ή python.

 

Αν έπρεπε να μείνουμε στο bash, θα έπρεπε να βασιστούμε στο ότι, όπως είπε ο NullScan, κανονικά θα είναι συνεχόμενα τα <PID>; Αν ήταν random;

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Υποθέτετε πολλά, νεαρέ. Μπορούμε να το κάνουμε ακόμα και σε -grsecurity πυρήνα ;-)

 

Μάθημα 2ο: /proc

 

Τι είναι το /proc

Στο /proc βρίσκεται mounted ένα virtual filesystem (τύπου `proc'). Το /proc είναι εικονικό με την έννοια ότι τα περιεχόμενά του δεν καταλαμβάνουν χώρο στο δίσκο και τα αρχεία που βρίσκονται στο /proc δεν έχουν πραγματικό περιεχόμενο. Αυτό που συμβαίνει είναι ότι ουσιαστικά σε κάθε προσπάθεια ανάγνωσης (read(2)) από κάποιο αρχείο ή κατάλογο του /proc απαντάει ο πυρήνας, επιστρέφοντας δυναμικά πληροφορίες σχετικές με αυτό που ζητήθηκε.

 

Τι υπάρχει στο /proc

Το /proc έχει μια ιεραρχική δομή, στην οποία ξεχωρίζουν τα εξής:

  • /proc/<pid>/: Οι κατάλογοι αυτοί περιέχουν πληροφορίες για τις διεργασίες
    με το αντίστοιχο pid.
  • /proc/sys/: Στον κατάλογο αυτό περιέχονται ρυθμίσεις σχετικές με τη λειτουργία του πυρήνα. Τα περιεχόμενα του καταλόγου αυτού είναι συνήθως και εγγράψιμα, ώστε να μπορεί να αλλάζουν δυναμικά οι ρυθμίσεις του πυρήνα όσο το σύστημα βρίσκεται σε λειτουργία. Ο κατάλογος αυτός αντιστοιχεί στο sysctl:
    >
    echo "1" > /proc/sys/net/ipv4/ip_forward
    ή
    sysctl -w net.ipv4.ip_forward=1
    


  • /proc/cpuinfo: επιστρέφει πληροφορίες σχετικά με τον επεξεργαστή του συστήματος
  • /proc/mounts: περιέχει πληροφορίες για όλα τα mounted filesystems

 

Ανατομία του /proc/<pid>

Αυτό που μας ενδιαφέρει στην προκειμένη περίπτωση είναι τα περιεχόμενα του /proc/<pid>. Κοιτώντας κανείς έναν τέτοιο κατάλογο βλέπει μεταξύ άλλων τα παρακάτω:

  • cmdline: Πως κλήθηκε το πρόγραμμα
  • cwd: link προς το directory στο οποίο «εργάζεται» η διεργασία
  • environ: Όλες οι environment variables που βλέπει
  • exe: link προς το αρχικό εκτελέσιμο
  • fd: Κατάλογος με symbolic links προς τους file descriptors
  • mem: Τα περιεχόμενα της μνήμης της διεργασίας
  • root: link για το root (αλλάζει με chroot() ας πούμε)
  • status: Πληροφορίες σχετικές με την κατάσταση της διεργασίας

 

Τι ξέρουμε για τη fork-bomb; Επειδή είπαμε ότι έτρεξε από το ίδιο shell, ξέρουμε (μέσω του history) το πως την έτρεξε κάποιος, ενώ μέσω της μεταβλητής $! ξέρουμε το pid του 1ου process. Επειδή με τη fork() κλωνοποιούνται αρκετά από τα περιεχόμενα του /proc/<pid> (μεταξύ των οποίων και το cmdline), όλα τα «παιδιά» της fork-bomb θα έχουν το ίδιο cmdline, στην προκειμένη περίπτωση "./fork\0", όπου \0 ένα null byte.

 

Επόμενο κεφάλαιο: πως μπορούμε να αξιοποιήσουμε τα δεδομένα αυτά χωρίς εξωτερικές εντολές, χρησιμοποιώντας μόνο shell builtins.

 

Για την ιστορία, η ps, και διάφορα άλλα προγράμματα, απλά διαβάζουν το /proc ;-)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

firewalker: ανάλογα. Βασικά αν έχεις αρκετή μνήμη/cpu θα είναι αποκρίσιμος. Και γενικά παραμένει αποκρίσιμος, απλά το timeslice που δίνει στο shell ειναι πολύ μικρό γιατί οι βόμβες από πίσω προσπαθούν να κάνουν συνέχεια fork(). Μπορείς όμως να το δοκιμάσεις ως απλός χρήστης με ένα ulimit -u 100 && ./fork-bomb και ο υπολογιστής σου θα παραμείνει αποκρίσιμος.

 

Πάνω απ' όλα κάνουμε ένα case study ομως, για να δείξουμε κάποιες δυνατότητες χρήσης του shell.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Πάμε λοιπόν για το τελευταίο κομμάτι:

 

Μάθημα 3ο: το shell ως υποκατάστατο των πάντων

 

Ξέρουμε λοιπόν ότι η βόμβα κλήθηκε ως ./fork. Θέλουμε να βρούμε ποια pid's λοιπόν έχουν το ./fork στο cmdline τους. Πώς θα διαβάσουμε το /proc/<pid>/cmdline όμως; Υπενθυμίζω οι δεν μπορούμε να κάνουμε fork(), άρα δεν παίζουν εξωτερικές εντολές, ούτε pipes, ούτε subshells, ούτε backquote substitutions.

 

Τα περισσότερα shells διαθέτουν ένα builtin ονόματι read, το οποίο διαβάζει από τη standard input μια γραμμή, και αποθηκεύει τις λέξεις της (που χωρίζονται με κενά ή \0 - στο bash) σε αντίστοιχες μεταβλητές. Έτσι π.χ.

>
# read cmd < /proc/1/cmdline
# echo $cmd
init [2]

Ειδικά στο zsh, η read θέλει και ένα

>-d ''

για να θεωρήσει το null byte delimiter.

 

Τώρα, χρησιμοποιώντας λίγο advanced shell globbing, μπορούμε επιτέλους να γράψουμε:

>
# pids=""
# cd /proc
# for pid in [0-9]*; do read cmd < $pid/cmdline; [[ $cmd == "./fork" ]] && pids="$pids $pid"; done

για bash ή

>
# pids=()
# cd /proc
# for pid in [0-9]*; do read -d '' cmd < $pid/cmdline; [[ $cmd == "./fork" ]] && pids=($pids $pid); done

για zsh και tcsh(?).

 

Το one-liner παραπάνω διαβάζει όλα τα cmdline από τα διαθέσιμα pids και ελέγχει ποια απ' αυτά περιέχουν την τιμή "./fork" στο πρώτο πεδίο τους. Αποθηκεύει τελικά σε έναν πίνακα ονόματι `pids' όλα τα pid που αντιστοιχούν στην εντολή "./fork".

 

Ο πίνακας `pids' περιέχει πλέον όλα τα pids που ανήκουν στη forkbomb, οπότε

>
# for pid in $pids; do kill -STOP $pid; done
# for pid in $pids; do kill -KILL $pid; done

Και καθαρίσαμε χρησιμοποιώντας μόνο builtins του shell (read & kill).

 

Όσοι θέλετε δοκιμάστε το παραπάνω σε ένα shell ως απλοί χρήστες, βάζοντας πρώτα ένα ulimit -u 100 για να κάνει τα πράγματα πιο εύκολα.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Παστρικές δουλειές, αυτό σημαίνει "ξέρω τα εργαλεία μου" !

 

Κατατοπιστικότατα τα μαθήματα, η ύλη εμπεδώθη :-)

 

 

όχι ότι δε θα το βρίσκαμε φυσικά... Ο Gtroza θα μας το σφυρούσε αργά ή γρήγορα ;)

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

cliche απάντηση #1 NEEEERDS!!

 

cliche απάντηση #2 get a life!

 

cliche απάντηση #3 στις μάνες σας το 'πατε?

 

σήμερα είδα μαθητούδια να βγαίνουν από φροντιστήριο, βαθμολογιές κτλ, gtroza, πιστεύω τα fork bombs δεν πέσανε γιατί λένε ανεβαίνουν οι βάσεις..

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

suser: Το bash είναι το shell που τρέχει κάθε φορά που ανοίγεις ένα terminal. Αναλαμβάνει να τρέξει τις εντολές που του λες και υποστηρίζει διάφορα χαρακτηριστικά, όπως το να συμπληρώνει λέξεις όταν πατάς tab, να παρέχει ένα στοιχειώδες περιβάλλον προγραμματισμού κλπ.

 

Το bash δεν είναι όμως το μοναδικό shell, αλλά υπάρχει μια πληθώρα από shells για να διαλέξεις. Το ότι είναι το default shell, δε σημαίνει ότι είναι και το καλύτερο. Πολλοί, μεταξύ αυτών και ο γράφων, είναι της άποψης ότι το zsh είναι καλύτερο shell για διαδραστική (interactive) χρήση.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

γειά σας κύριε

 

η γιαγιά μου είχε πρόβλημα με το laptop της, και την βοήθησα να εγκαταστήσει linux για να βάλουν και οι άλλες κυρίες στο ΚΑΠΗ.

 

ελπίζω να είναι δικαιολογημένη η απουσία που πήρα

 

πρόσεξα όμως οτι οι άλλοι συμμαθητές μου, δεν ανατρέχουν σε άλλες πηγές εκτός των σημειώσεων που μας δίνετε !:mrgreen:

.

Συνδέστε για να σχολιάσετε
Κοινοποίηση σε άλλες σελίδες

Αρχειοθετημένο

Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.


  • Δημιουργία νέου...