Сценарії BASH є невід’ємною частиною операційної системи Linux і відіграють важливу роль у виконанні автоматизованих завдань, розробці скриптів та управлінні системою. BASH (Bourne Again SHell) – це командний інтерфейс та мова сценаріїв, які дозволяють користувачам створювати послідовності команд для виконання різних завдань безпосередньо з командного рядка. Від початкового запуску програми до складних автоматизованих задач, сценарії BASH забезпечують потужний інструментарій для керування Linux-системою. Гнучкість та Ефективність: Сценарії BASH надають користувачам велику гнучкість у виконанні завдань. Вони дозволяють автоматизувати рутинні операції, спрощують процеси роботи з файлами та каталогами, і дозволяють створювати послідовності команд для виконання складних завдань.
Скрипти та Інтерактивність: Ви можете створювати скрипти BASH, які автоматизують задачі і виконують їх в автоматичному режимі, або використовувати інтерактивний режим для взаємодії з системою під час виконання команд. Робота з Файлами та Каталогами: Сценарії BASH надають потужні засоби для керування файлами і каталогами. Вони дозволяють копіювати, переміщати, перейменовувати, видаляти та переглядати вміст файлів та каталогів. Завдання та Розклади: Ви можете створювати скрипти BASH для автоматизації завдань та розкладів, що дозволяє виконувати певні дії в заданий час або за певних умов. Управління Системою: Сценарії BASH дозволяють управляти системними ресурсами, службами, користувачами та іншими параметрами операційної системи Linux. Легкість Навчання та Застосування: Вивчення BASH-сценаріїв є досить доступним для початківців і досвідчених користувачів. Сценарії можуть бути написані в текстовому редакторі та запущені з командного рядка. Спільнота та Ресурси: Linux має велику спільноту користувачів, що означає, що ви можете знайти безліч ресурсів, які допоможуть вам з розробкою та розвитком ваших навичок BASH-сценаріїв. Сценарії BASH у Linux – це потужний інструмент для автоматизації, управління та розвитку операційних систем. Вони дозволяють здійснювати різні завдання, починаючи від простих команд до складних автоматизованих процесів, і відкривають широкі можливості для роботи з Linux.
У цьому розділі ми створюємо кілька простих скриптів оболонки bash, щоб почати з написання сценаріїв. Ми будемо додавати можливості та функції в міру просування, в кінцевому підсумку створюючи сценарій, здатний знаходити потенційні цілі атаки за різними IP-адресами.
Щоб стати елітним хакером, вам також знадобиться можливість писати сценарії на одній з широко використовуваних скриптових мов, таких як Ruby (експлойти Metasploit написані на Ruby), Python (багато інструментів злому є скриптами Python) або Perl (Perl – найкраща мова написання текстових сценаріїв).
Оболонка – це інтерфейс між користувачем і операційною системою, що дозволяє маніпулювати файлами і запускати команди, утиліти, програми і багато іншого. Перевага оболонки полягає в тому, що ви виконуєте ці завдання відразу з комп’ютера, а не через абстракцію, на зразок графічного інтерфейсу, що дозволяє налаштувати ваше завдання під ваші потреби. Для Linux доступний ряд різних оболонок, включаючи оболонку Korn, Z-оболонка, оболонка C і оболонка Борна, більш відома як bash.
Оскільки оболонка bash доступна майже у всіх дистрибутивах Linux і UNIX (включаючи macOS і Kali), ми будемо використовувати виключно оболонку bash.
Оболонка bash може запускати будь-які системні команди, утиліти або програми, які може запускати ваш звичайний командний рядок, але вона також включає деякі власні вбудовані команди. Таблиця 81 далі в розділі дає посилання на деякі корисні команди, які знаходяться в оболонці bash.
У попередніх розділах ви використовували команди cd, pwd, set та umask. У цьому розділі ви будете використовувати ще дві команди: команду echo, вперше використану в главі 7, яка відображає повідомлення на екрані, і команду читання, яка зчитує дані і зберігає їх десь в іншому місці. Лише вивчення цих двох команд дозволить вам створити простий, але потужний інструмент.
Вам знадобиться текстовий редактор для створення скриптів оболонки. Ви можете використовувати будь-який текстовий редактор Linux, який вам найбільше подобається, включаючи vi, vim, emacs, gedit, kate тощо. Я буду використовувати Leafpad у цих підручниках, як і в попередніх розділах. Використання іншого редактора не повинно мати ніякого значення у вашому сценарії або його функціональності.
Для вашого першого сценарію ми почнемо з простої програми, яка повертає на екран повідомлення з написом «Привіт, хакери-встаньте!» Відкрийте текстовий редактор і поїхали. Для початку вам потрібно повідомити своїй операційній системі, який інтерпретатор ви хочете використовувати для сценарію. Для цього введіть шебанг, який представляє собою комбінацію хеш-знака і знака оклику, ось так:
#!
Потім ви йдете за шебангом (#!) з /bin/ bash, щоб вказати, що ви хочете, щоб операційна система використовувала інтерпретатор оболонки bash. Як ви побачите в наступних розділах, ви також можете використовувати шебанг для використання інших інтерпретаторів, таких як Perl або Python. Тут ви хочете використовувати інтерпретатор bash, тому введіть наступне:
#! /bin/bash
Далі введіть команду echo , яка наказує системі просто повторити (або відлуння) Ваш монітор все, що виконує команду.
У цьому випадку ми хочемо, щоб система відповіла нам «Привіт, хакери-встаньте!», як це зроблено в списку 81. Зверніть увагу, що текст або повідомлення, яке ми хочемо повторити, повинні бути взяті в подвійні лапки.
#! «Привіт, хакери-встаньте!»
Тут ви також бачите рядок, якому передує хеш-позначка (#). Це коментар, який ви залишаєте собі або комусь іншому, хто читає код, щоб пояснити, що ви робите в сценарії. Програмісти використовують коментарі на кожній мові кодування. Ці коментарі не читаються і не виконуються інтерпретатором, тому вам не потрібно турбуватися про те, що ваш код зіпсується. Їх видно тільки людині. Оболонка bash знає, що рядок є коментарем, якщо він починається з символу # .
Тепер збережіть цей файл як HelloHackersArise без розширення та закрийте текстовий редактор.
За замовчуванням новостворений скрипт bash не виконується навіть вами, власником. Давайте подивимося на дозволи для нашого нового файлу в командному рядку, використовуючи cd для переміщення в каталог, а потім ввівши ls -l. Він повинен виглядати приблизно так:
kali >ls-l snip rwrr 1 root root 42 Oct 22 14:32 HelloHackersArise snip
Як бачите, наш новий файл має дозволи rw-r–r– (644). Як ви дізналися з розділу 5, це означає, що власник цього файлу має лише дозволи на читання (r) та запис (w), але не має дозволів на виконання (x). Група та всі інші користувачі мають лише дозволи на читання. Нам потрібно дати собі дозволи на виконання, щоб запустити цей скрипт. Ми змінюємо дозволи командою chmod, як ви бачили в главі 5.Щоб надати власнику, групі та всім іншим дозволи на виконання, введіть наступне:
kali >chmod755HelloHackersArise
Тепер, коли ми робимо довгий список у файлі, наприклад, ми бачимо, що у нас є дозволи на виконання:
kali >ls-l snip rwx rx rx 1 root root 42 Oct 22 14:32 HelloHackersArise snip
Сценарій тепер готовий до виконання!
Щоб запустити наш простий скрипт, введіть наступне:
kali >./HelloHackersArise
Символ ./ перед іменем файлу повідомляє системі, що ми хочемо виконати цей скрипт у файлі HelloHackersArise з поточного каталогу. Він також повідомляє системі, що якщо в іншому каталозі є інший файл з назвою HelloHackersArise, будь ласка, ігноруйте його і запускайте HelloHackersArise лише в поточному каталозі. Може здатися малоймовірним, що у вашій системі є інший файл з таким ім’ям, але рекомендується використовувати ./ під час виконання файлів, оскільки це локалізує виконання файлу в поточному каталозі, і багато каталогів матимуть дублікати імен файлів, таких як start та setup.
Коли ми натискаємо ENTER, наш дуже простий сценарій повертає наше повідомлення на монітор: Привіт, хакериArise! Успіх! Ви щойно завершили свій перший сценарій оболонки!
Отже, тепер перед нами простий сценарій. Все, що він робить, це повторює повідомлення до стандартного виводу.
Якщо ми хочемо створити більш просунуті скрипти, нам, швидше за все, доведеться додати деякі змінні.
Змінна – це область зберігання, яка може утримувати щось у пам’яті. Це “щось” може бути деякими літерами, словами (рядками) або цифрами. Вона відома як змінна, оскільки значення, що містяться в ній, є мінливими; Це надзвичайно корисна функція для додавання функціональності до сценарію.
У нашому наступному сценарії ми додамо функціональність, щоб запитати користувачеві його ім’я, розмістити все, що він вводить, у змінну, потім запитати користувача про главу, в якій він знаходиться в цій книзі, і помістити цей вхід з клавіатури в змінну. Після цього ми повторимо користувачеві привітальне повідомлення, яке містить їх ім’я та розділ. Відкрийте новий файл у текстовому редакторі та введіть скрипт, показаний у списку 82.
➊ #! /bin/bash
➋ # Це ваш другий сценарій bash. У цьому ви підказуєте /# користувач для введення, помістіть вхід у змінну та /# відображення вмісту змінної в рядку.
➌ echo “Як тебе звати?”прочитати назву
➍ echo “Яку главу ви читаєте в Основах Linux для хакерів?”прочитати главу
➎ echo “Ласкаво просимо” $name “до розділу” $chapter “основ Linux для хакерів!”
Список 82: Простий скрипт, що використовує змінні
Відкриваємося за допомогою #! /bin/bash, щоб повідомити системі, що ми хочемо використовувати інтерпретатор bash для цього сценарію ➊. Потім ми додаємо коментар, який описує скрипт і його функціональність ➋. Після цього ми запитуємо користувачеві його ім’я і просимо інтерпретатора прочитати вхідні дані і помістити його в змінну, яку ми називаємо name ➌. Потім ми пропонуємо користувачеві ввести главу, над якою вони зараз працюють у цій книзі, і ми знову читаємо введення клавіатури у змінну, цього разу під назвою глава ➍.
У заключному рядку ми будуємо лінію виводу, яка вітає читача за його ім’ям до розділу, в якому він знаходиться ➎. Використовуємо команду echo і надаємо текст, який хочемо відобразити на екрані в подвійних лапках. Потім заповнити ім’я та номер глави
Введеному користувачеві додаємо змінні там, де вони повинні з’явитися в повідомленні. Як зазначено в главі 7, для використання значень, що містяться в змінних, необхідно перед ім’ям змінної позначитися символом $.
Збережіть цей файл як WelcomeScript.sh. Розширення .sh є конвенцією для файлів сценаріїв. Можливо, ви помітили, що ми не включили розширення раніше; Це не обов’язково, і якщо ви залишите розширення вимкненим, файл збережеться як файл сценарію оболонки за замовчуванням.
Тепер давайте запустимо цей сценарій. Не забудьте спочатку дати собі дозвіл за допомогою chmod ; інакше операційна система насварить вас повідомленням «Відмовлено в дозволі ».
kali >./WelcomeScript.sh What is your name? OccupytheWeb What chapter are you on in Linux Basics for Hackers? 8 Welcome OccupytheWeb to Chapter 8 of Linux Basics for Hackers!
Як бачите, ваш скрипт брав вхідні дані від користувача, розміщував їх у змінних, а потім використовував ці входи, щоб привітати користувача.
Це простий скрипт, але він навчив вас, як використовувати змінні та приймати введення з клавіатури. Це обидві найважливіші концепції в сценарії, які вам потрібно буде використовувати в більш складних сценаріях у майбутньому.
Тепер, коли у вас є деякі базові навички сценаріїв, давайте перейдемо до деяких трохи більш просунутих сценаріїв, які мають реальне застосування до злому. Ми скористаємося прикладом зі світу злому чорних капелюхів. Чорні хакери – це ті, хто має зловмисні наміри, такі як крадіжка номерів кредитних карток або спотворення веб-сайтів. Білі хакери – це ті, хто має добрі наміри, наприклад, допомагати розробникам програмного забезпечення або системним адміністраторам зробити свої системи більш безпечними. Хакери сірого капелюха – це ті, хто схильний переміщатися між цими двома крайнощами.
Перш ніж продовжити, вам потрібно ознайомитися з простим, але важливим інструментом під назвою nmap, який типово встановлюється на Kali. Ви, напевно, чули це ім’я; Nmap використовується для зондування системи, щоб побачити, чи підключена вона до мережі, і з’ясувати, які порти відкриті. З виявлених відкритих портів можна припустити, що
Сервіси працюють за цільовою системою. Це найважливіший навик для будь-якого хакера або системного адміністратора.
У найпростішому вигляді синтаксис запуску сканування nmap виглядає так:
nmap <type of scan><target IP><optionally, target port>
Чи не занадто складно. Найпростішим і найнадійнішим скануванням nmap є сканування TCP connect, позначене перемикачем -sT в nmap. Отже, якщо ви хочете відсканувати IP-адресу 192.168.181.1 за допомогою сканування TCP, ви введете наступне:
nmap -sT 192.168.181.1
Щоб зробити крок далі, якщо ви хочете виконати TCP-сканування адреси 192.168.181.1, дивлячись на те, чи був відкритий порт 3306 (порт за замовчуванням для MySQL), ви можете ввести це:
nmap -sT 192.168.181.1 -p 3306
Тут -p позначає порт, який потрібно просканувати. Спробуйте це зараз у своїй системі Kali.
На момент написання цієї статті існує хакер, який відбуває термін у федеральній в’язниці США на ім’я Макс Батлер, також відомий у всьому світі хакерів як Max Vision. Макс був таким собі хакером у сірому капелюсі. Вдень він був професіоналом з ІТ-безпеки в Кремнієвій долині, а вночі крав і продавав номери кредитних карток на чорному ринку. Свого часу він керував найбільшим у світі чорним ринком кредитних карток CardersMarket. Тепер Макс відбуває 13-річний тюремний термін, одночасно допомагаючи команді реагування на комп’ютерні надзвичайні ситуації (CERT) у Піттсбурзі захищатися від хакерів.
За кілька років до того, як Макса спіймали, він зрозумів, що система Aloha Point of Sale (POS), яка використовується багатьма невеликими ресторанами, має вбудований бекдор технічної підтримки. У цьому випадку бекдор дозволяв технічній підтримці допомагати своїм клієнтам. Технічна підтримка Aloha могла отримати доступ до системи кінцевого користувача через порт 5505, щоб надати допомогу, коли користувач покликав на допомогу. Макс зрозумів, що якщо він знайде систему, підключену до Інтернету з POS-системою Aloha, він зможе отримати доступ до системи з привілеями системного адміністратора через порт 5505. Макс зміг увійти в багато з цих систем і вкрасти десятки тисяч номерів кредитних карт.
Зрештою, Макс хотів знайти кожну систему, в якій був відкритий порт 5505, щоб він міг перейти від крадіжки тисяч номерів кредитних карток до крадіжки мільйонів. Макс вирішив написати скрипт, який сканував би мільйони IP-адрес у пошуках систем з відкритим портом 5505. Звичайно, більшість систем не мають відкритого порту 5505, тому, якщо б вони це зробили, то, швидше за все, вони керували приреченою точкою продажу Aloha. Він міг запускати цей сценарій під час роботи вдень, а потім вночі зламати ті системи, які були визначені як такі, що мають відкритий порт 5505.
Наше завдання полягає в тому, щоб написати скрипт, який буде майже ідентичний сценарію Макса, але замість того, щоб сканувати порт 5505, як це зробив Макс, наш скрипт буде сканувати системи, підключені до всюдисущої онлайн-бази даних MySQL. MySQL – це база даних з відкритим вихідним кодом, яка використовується за мільйонами веб-сайтів; ми будемо працювати з MySQL у розділі 12. За замовчуванням MySQL використовує порт 3306. Бази даних – це “золоте руно”, яке шукає майже кожен хакер чорного капелюха, оскільки вони часто містять номери кредитних карток та особисту інформацію (PII), що дуже цінно на чорному ринку.
Перш ніж ми напишемо сценарій для сканування загальнодоступних IP-адрес в Інтернеті, давайте візьмемося за набагато менше завдання. Замість того, щоб сканувати глобус, давайте спочатку напишемо скрипт для сканування порту 3306 у локальній мережі, щоб побачити, чи дійсно працює наш скрипт. Якщо це так, ми можемо легко відредагувати його, щоб виконати набагато більше завдання.
У текстовому редакторі введіть сценарій, показаний у списку 83.
➊ #! /bin/bash ➋ # This script is designed to find hosts with MySQL installed nmap ➌sT 192.168.181.0/24 ➍p 3306 ➎>/dev/null ➏oG MySQLscan ➐ cat MySQLscan | grep open > MySQLscan2 ➑ cat MySQLscan2
Почнемо з шебанга і перекладача для використання ➊. Давайте прослідкуємо за цим за допомогою
коментар, щоб пояснити, що робить сценарій ➋.
Тепер давайте скористаємося командою nmap, щоб запросити сканування TCP ➌ на нашій локальній мережі, шукаючи порт 3306 ➍. (Зверніть увагу, що ваші IP-адреси можуть відрізнятися; у вашому терміналі використовуйте кнопку команда ifconfig у Linux або команда ipconfig у Windows, щоб визначити вашу IP-адресу.) Щоб залишатися прихованими, ми також надсилаємо стандартний вихід nmap, який зазвичай з’являється на екрані, у спеціальне місце в Linux, де він зникає ➎. Ми робимо це на локальній машині, тому це не має великого значення, але якщо ви хочете використовувати сценарій віддалено, ви хотіли б приховати вихідні дані nmap. Потім ми надсилаємо вихідні дані сканування до файлу з назвою MySQLscan у форматі grepable ➏, що означає формат, над яким grep може працювати.
Наступний рядок показує файл MySQLscan, в якому ми зберегли вихідні дані, а потім конвеєри, які виводять для grep для фільтрації рядків, які містять ключове слово open ➐. Потім ми поміщаємо ці рядки у файл з назвою MySQLscan2 ➑.
Нарешті, ви відображаєте вміст файлу MySQLscan2. Цей кінцевий файл повинен містити лише рядки виводу з nmap з хостами, у яких відкрито порт 3306. Збережіть цей файл як MySQLscanner.sh і дайте собі дозволи на виконання за допомогою chmod 755.
Виконайте скрипт так:
kali >./MySQLscanner.sh host: 192.168.181.69 () Ports: 3306/open/tcp//mysql///
Як ми бачимо, цей сценарій зміг ідентифікувати єдину IP-адресу в моїй локальній мережі з запущеним MySQL. Ваші результати можуть відрізнятися, залежно від того, чи запускаються якісь порти інсталяції MySQL у вашій локальній мережі, звичайно.
Тепер ми хочемо адаптувати цей скрипт, щоб зробити його застосовним не тільки до вашої власної локальної мережі. Цей сценарій було б набагато простіше використовувати, якби він міг запитати користувача про діапазон IP-адрес, які він хотів сканувати, і порт, який потрібно шукати, а потім використовувати ці дані.
Давайте подивимося, як ви можете використовувати змінні, щоб зробити цей сценарій більш гнучким та ефективним. Додавання підказок та змінних до нашого хакерського сценарію.
У текстовому редакторі введіть сценарій:
#! /bin/bash ➊ echo "Введіть початкову IP-адресу: " ➋ читайте FirstIP ➌ echo "Введіть останній октет останньої IP-адреси: " читайте LastOctetIP ➍ echo "Введіть номер порту, який потрібно сканувати: " читати порт ➎ nmap sT $FirstIP$LastOctetIP p $port >/dev/null oG MySQLscan ➏ cat MySQLscan | grep open > MySQLscan2 ➐ cat MySQLscan2
Список 84: Ваш вдосконалений сканер портів MySQL
Перше, що нам потрібно зробити – замінити вказану підмережу діапазоном IP-адрес. Ми створимо змінну з назвою FirstIP і другу змінну з іменем LastOctetIP для створення діапазону, а також змінну з іменем порту для номера порту (останній октет – це остання група цифр після третього періоду в IP-адресі. В IP-адресі 192.168.1.101 останній октет – 101).
Нам також потрібно підказати користувачеві ці значення. Ми можемо зробити це за допомогою команди echo, яку ми використовували в списку 81.
Щоб отримати значення для змінної FirstIP, відлуння “Введіть початкову IP-адресу : ” на екран, запитуючи у користувача першу IP-адресу, яку він хоче сканувати ➊. Побачивши це підказку на екрані, користувач введе першу IP-адресу, тому нам потрібно зафіксувати ці дані від користувача.
Ми можемо зробити це за допомогою команди read, за якою слідує ім’я змінної, яку ми хочемо зберегти на вході ➋. Ця команда помістить введений користувачем IP-адреса в змінну FirstIP. Тоді ми можемо використовувати це значення в FirstIP у всьому нашому сценарії.
Ми зробимо те ж саме для змінних LastOctetIP ➌ та порту ➍, запропонувавши користувачеві ввести інформацію, а потім використовуючи команду читання, щоб захопити її.
Далі нам потрібно відредагувати команду nmap в нашому скрипті, щоб використовувати змінні, які ми щойно створили та заповнили. Щоб використовувати значення, збережене в змінній, ми просто передмовляємо ім’я змінної з $, як в $port, наприклад. Отже, за адресою ➎ ми скануємо діапазон IP-адрес, починаючи з першої IP-адреси користувача через другу IP-адресу введення користувача, і шукаємо конкретний вхід порту користувачем. Ми використали змінні замість підмережі для сканування та порт, щоб визначити, що потрібно сканувати. Символ переспрямування > повідомляє стандартному виводу nmap, який зазвичай надходить на екран, замість цього перейти до /dev/null (/dev/null — це просто місце для надсилання виводу, щоб він зник). Потім ми надсилаємо вихідні дані у форматі, який можна переглянути, до файлу, який ми назвали MySQLscan.
Наступний рядок залишається таким же, як і в нашому простому сканері: він виводить вміст файлу MySQLscan, передає його в grep, де він фільтрується для рядків, які містять ключове слово open, а потім відправляє цей вихід до нового файлу з назвою MySQLscan2 ➏. Нарешті, ми показуємо вміст файлу MySQLscan2 ➐.
Якщо все працює належним чином, цей сценарій сканує IP-адреси від першої адреси введення до останньої адреси введення, шукає вхідний порт, а потім повідомляє лише про IP-адреси, для яких відкритий призначений порт. Збережіть файл сценарію як MySQLscannerAdvanced, не забуваючи дати собі дозвіл на виконання.
Тепер ми можемо запустити наш простий сценарій сканера зі змінними, які визначають, який діапазон IP-адрес і порт сканувати, не редагуючи сценарій кожного разу, коли ми хочемо запустити сканування:
kali >./MySQLscannerAdvanced.sh Enter the starting IP address : 192.168.181.0 Enter the last IP address : 192.168.181.255 Enter the port number you want to scan for : 3306 Host: 192.168.181.254 ()Ports:3306/open/tcp//mysql/
Сценарій запитує користувача про першу IP-адресу, останню IP-адресу, а потім порт для сканування. Після збору цих відомостей сценарій виконує сканування nmap і створює звіт про всі IP-адреси в діапазоні, для яких відкрито вказаний порт. Як бачите, навіть найпростіші сценарії можуть створити потужний інструмент.
Як і було обіцяно, таблиця 81 дає вам список деяких корисних команд, вбудованих в bash.
Таблиця 81: Вбудовані команди Bash
: Повертає 0 або правду (Returns 0 or true)
. Виконує сценарій оболонки
bg Переносить роботу на другий план
break Вихід із поточного циклу
cd Змінює каталог
continue Відновлює поточний цикл
echo Відображає аргументи команди
eval Обчислює наступний вираз
exec Виконує наступну команду без створення нового процесу
exit Виходить із оболонки
export Робить змінну або функцію доступною для інших програм
fg Виводить роботу на передній план
getopts Розбирає аргументи сценарію оболонки
jobs Перераховує фонові (bg) роботи
pwd Відображає поточний каталог
read Читає рядок зі стандартного введення
readonly Оголошує змінну як лише для читання
set Перераховує всі змінні
shift Переміщує параметри вліво
test Оцінює аргументи
[ Виконує умовну перевірку
times Друкує час користувача та системи
trap Вловлює сигнал
type Показує, як кожен аргумент інтерпретуватиметься як команда
umask Змінює дозволи за замовчуванням для нового файлу
unset Видаляє значення зі змінної або функції
wait Чекає завершення фонового процесу
Створення сценаріїв є важливою навичкою для будь-якого хакера або системного адміністратора. Це дозволяє автоматизувати завдання, які зазвичай займають години вашого часу, і після збереження сценарію його можна використовувати знову і знову.
Ми використовували матеріали з книги “LINUX BASICS FOR HACKERS”, які написав William Pollock