<?xml version="1.0" encoding="utf-8" ?><rss version="2.0" xmlns:tt="http://teletype.in/" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:media="http://search.yahoo.com/mrss/"><channel><title>KyouKiSu</title><generator>teletype.in</generator><description><![CDATA[KyouKiSu]]></description><image><url>https://img4.teletype.in/files/7c/44/7c447f14-d464-44c6-ae24-48b935d7b6c2.png</url><title>KyouKiSu</title><link>https://teletype.in/@kyoukisu</link></image><link>https://teletype.in/@kyoukisu?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu</link><atom:link rel="self" type="application/rss+xml" href="https://teletype.in/rss/kyoukisu?offset=0"></atom:link><atom:link rel="next" type="application/rss+xml" href="https://teletype.in/rss/kyoukisu?offset=10"></atom:link><atom:link rel="search" type="application/opensearchdescription+xml" title="Teletype" href="https://teletype.in/opensearch.xml"></atom:link><pubDate>Mon, 06 Apr 2026 20:07:02 GMT</pubDate><lastBuildDate>Mon, 06 Apr 2026 20:07:02 GMT</lastBuildDate><item><guid isPermaLink="true">https://teletype.in/@kyoukisu/advanced_reentrancy</guid><link>https://teletype.in/@kyoukisu/advanced_reentrancy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu</link><comments>https://teletype.in/@kyoukisu/advanced_reentrancy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu#comments</comments><dc:creator>kyoukisu</dc:creator><title>Advanced Reentrancy</title><pubDate>Tue, 26 Jul 2022 03:01:49 GMT</pubDate><media:content medium="image" url="https://img1.teletype.in/files/c4/99/c4997937-8af9-4d40-bbf6-70c55394f422.png"></media:content><description><![CDATA[<img src="https://img3.teletype.in/files/61/66/616675b1-1d9c-4406-9be0-85275824ec46.jpeg"></img>Всем привет, с вами @kyoukisu (кёкису). В этот раз мы рассмотрим детально атаку reentrancy на более сложном примере. Данная статья является вольным переводом+редактурой информации с Cross-Contract Reentrancy Attack.]]></description><content:encoded><![CDATA[
  <figure id="99ON" class="m_custom">
    <img src="https://img3.teletype.in/files/61/66/616675b1-1d9c-4406-9be0-85275824ec46.jpeg" width="1070.2121588089328" />
  </figure>
  <p id="rtFG">Всем привет, с вами <a href="https://t.me/kyoukisu" target="_blank">@kyoukisu</a> (кёкису). В этот раз мы рассмотрим детально атаку <strong>reentrancy</strong> на более сложном примере. Данная статья является вольным переводом+редактурой информации с <a href="https://inspexco.medium.com/cross-contract-reentrancy-attack-402d27a02a15" target="_blank">Cross-Contract Reentrancy Attack</a>.</p>
  <p id="5Nhl">Если вам что-то непонятно, тыкайте по встроенным ссылкам, они здесь не просто так.</p>
  <p id="mrzX">Перед прочтением обязательно ознакомьтесь <a href="/@kyoukisu/attacks_reentrancy">с моей первой статьей про reentrancy</a>.</p>
  <p id="PXMY">Исходники кода будут ссылками под картинками.</p>
  <h2 id="PHZs">Еще один вид Reentrancy?</h2>
  <p id="a76G">Ранее мы рассматривали <strong>reentrancy </strong>внутри одной функции и между несколькими, но такие очевидные уязвимости оставляют достаточно редко, ведь есть множество простых решений защиты от них (<a href="https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard" target="_blank">ReentrancyGuard</a> от OpenZeppelin). Менее очевидная уязвимость возникает между разными смарт-контрактами, а именно, когда состояние из одного контракта используется в другом контракте, но это состояние не полностью обновляется перед вызовом.</p>
  <p id="gxSB"><em><strong>Cross-Contract Reentrancy </strong>возможна, когда соблюдаются следующие условия:</em></p>
  <ol id="MtUM">
    <li id="a60a">Есть места передачи потока управления.</li>
    <li id="ksfL">Состояния одного контракта используются в другом контракте.</li>
    <li id="bOCT">Неграмотное построение взаимодействия контрактов.</li>
  </ol>
  <h2 id="G8l3">Пример Cross-Contract Reentrancy</h2>
  <h3 id="zS9h">Первый контракт</h3>
  <p id="Dzyl">Рассмотрим простенький ERC20 контракт <strong>VaultToken </strong>(далее $VT). Обычный ровный токен, имеет свое хранилище бля обеспечения, почти стейбл. В нем используется интерфейс UniswapV2 роутера для того, чтобы свапать сторонние токены, на что-то более надежное, чтобы не стать <a href="https://www.coindesk.com/markets/2022/05/15/the-collapse-of-terra-was-devastating-but-there-is-still-hope-for-crypto/" target="_blank">холдером $LUNA и $UST</a>. Инфу о UniswapV2 роутере можно глянуть в <a href="https://docs.uniswap.org/protocol/V2/reference/smart-contracts/router-02" target="_blank">доках юнисвапа</a>.</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="vkA4"><a href="https://uniswap.org/" target="_blank"><u>Uniswap</u></a> - это децентрализованная криптовалютная биржа (DEX). Она работает на блокчейне Ethereum и полностью автоматизирована смартконтрактами. <a href="https://habr.com/ru/post/572034/" target="_blank">Подробнее про работу Uniswap&#x27;а</a>.</p>
  </section>
  <figure id="rzgT" class="m_column">
    <img src="https://img4.teletype.in/files/f6/ce/f6cea7d9-d030-4cb5-a083-bf418e36d0a6.png" width="592" />
    <figcaption>без комментариев</figcaption>
  </figure>
  <h3 id="Zeau" data-align="center"><strong>Vault.sol</strong></h3>
  <figure id="OtJ2" class="m_custom">
    <img src="https://img3.teletype.in/files/a4/24/a4245fcd-e153-4459-ac20-052908a82712.png" width="1069.574385510996" />
    <figcaption><a href="https://gist.github.com/inspexAuditor/6ecc218b0bf4f178cfa3728bec49c116#file-vault-sol" target="_blank">source</a></figcaption>
  </figure>
  <p id="4nBg"><em>Некоторые особенности</em>:</p>
  <ul id="0XGq">
    <li id="4ZA3">При создании контракта в конструкторе (18 строчка) мы указываем <strong>_router</strong> или же интерфейс UniswapV2, а также <strong>_baseToken </strong>сторонний токен, который будет вноситься пользователями и храниться в контракте, чаще всего это стейбл или эфир.</li>
    <li id="aVgp">В коде можно заметить <strong>_burn</strong>, <strong>_mint</strong>, <strong>totalSupply</strong>; это стандартизированные функции <strong><a href="https://docs.openzeppelin.com/contracts/2.x/api/token/erc20" target="_blank">ERC20.sol</a></strong>, от которого мы наследуемся.</li>
    <li id="IBlh">Выдача токена <strong>$VT</strong> напрямую зависит от доли юзера в общих активах <strong>baseToken</strong> контракта. Расчеты относительно этой доли происходят в функциях <strong>shareToAmount </strong>и <strong>amountToShare </strong>(23 и 27 строчки соответственно).</li>
  </ul>
  <h3 id="mR3K"></h3>
  <h3 id="POsy"><strong>Что происходит в контракте?</strong> </h3>
  <p id="eIrN">Юзеры вносят какие-то токены <strong>_srcToken, </strong>неважно какие, пока они сделаны по стандарту ERC20 и имеют ликвидность на Uniswap&#x27;e, чтоб контракт мог их сбыть по флору через функцию<strong> swapAndDeposit.</strong> Потом юзеры жмут <strong>deposit </strong>и минтят <strong>$VT</strong>, при вызове<strong> withdraw </strong>происходит все с точностью да наоборот - сжигают <strong>$VT</strong> и выводят <strong>baseToken,</strong> на свои скам токены юзер сам будет менять его.</p>
  <p id="lmpD">На каждой функции контракта <strong>Vault</strong>, которая изменяет его стейт, висит модификатор <strong>nonReentrant </strong>из контракта <strong>ReentrancyGuard.sol,</strong> что обеспечивает защиту от повторного входа <u>в данную функцию</u>. </p>
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="yMnU">Модификатор - особая функция, которая оборачивается вокруг другой.</p>
  </section>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="XmEZ">Если вспомнить прошлую статью, то <strong>nonReentrant</strong> по своей сути является мьютексом.</p>
  </section>
  <p id="4J0H"></p>
  <h3 id="VqRE" data-align="center">ReentrancyGuard.sol</h3>
  <figure id="Ibs6" class="m_custom">
    <img src="https://img1.teletype.in/files/43/9d/439d68ef-c731-4437-a248-675ce2dd8fe6.png" width="1070.1718213058416" />
    <figcaption><a href="https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v4.7.1/contracts/security/ReentrancyGuard.sol" target="_blank">source</a></figcaption>
  </figure>
  <section style="background-color:hsl(hsl(170, 33%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="amia">Поэтому что бы ни пытался сделать злоумышленник <u>с единственным контрактом</u> <strong>Vault.sol</strong>, при рекурсивных вызовах он будет упираться в <code>require</code> функции <strong>_nonReentrantBefore</strong>. Однако это нас не остановит от reentrancy между контрактами.</p>
  </section>
  <figure id="R9Td" class="m_column">
    <img src="https://img1.teletype.in/files/c2/c1/c2c1cad7-7742-428a-9c73-08d1f7628afd.png" width="1199" />
    <figcaption>наивное применение nonReentrant не спасет вас от reentrancy между несколькими контрактами</figcaption>
  </figure>
  <h3 id="3JcJ">Второй контракт</h3>
  <p id="Aojm">Предположим, что у нас есть еще один контракт, некий <strong>ICOGov</strong>, позволяющий юзерам обменивать <strong>$VT</strong> на новый токен <strong>$GOV - </strong>какая-то донная P2E игрушка, проводит ICO, IGO на платформе токена <strong>$VT</strong> (можете представить здесь панкейк) и хочет бабок. Количество получаемых токенов определяется числом инвестированных <strong>$VT</strong> и курсом обмена <strong>tokenPrice.</strong></p>
  <p id="Pvfa"></p>
  <h3 id="hlr7" data-align="center"><strong>ICOGov.sol</strong></h3>
  <figure id="G6eN" class="m_custom">
    <img src="https://img2.teletype.in/files/d7/31/d731f6d9-3b0d-4b98-87dd-bc0550a7a2df.png" width="1070" />
    <figcaption><a href="https://gist.github.com/inspexAuditor/0fdf0ffff136296317137f82f9ecfe61#file-icogov-sol" target="_blank">source</a></figcaption>
  </figure>
  <p id="MQhJ">При создании контракта в конструктор передаются токен <strong>$GOV</strong>, токен <strong>$VT</strong>, <strong>_treasury</strong> адрес, куда будут скидываться все токены <strong>$VT</strong> при обмене, а также цену токена.</p>
  <p id="SDOq">Функция <strong>buyToken </strong>как раз таки отвечает за обмен токенов, и, как мы видим, на ней тоже висит модификатор <strong>nonReentrant.</strong></p>
  <p id="GyWr"></p>
  <h2 id="V3yV">Находим уязвимость</h2>
  <p id="j6mt">Первая вещь, которую мы должны заметить в контракте <strong>Vault</strong>, это то, что есть передача потока управления контракту <strong>_srcToken</strong> в функции <strong>swapAndDeposit</strong>. </p>
  <figure id="KvLW" class="m_custom">
    <img src="https://img2.teletype.in/files/de/4b/de4b9795-3290-4a7d-97a7-b58d9890ec56.png" width="1070" />
  </figure>
  <p id="quoL">Вторая заключается в функции <strong>buyToken</strong> контракта <strong>ICOGov</strong>, т.к. она использует стейт <strong>Vault&#x27;а, </strong>обращаясь к нему за <strong>shareToAmount</strong>.</p>
  <figure id="57QB" class="m_custom">
    <img src="https://img4.teletype.in/files/f6/0c/f60c8c1f-4f13-40de-8a11-a61087a17dbc.png" width="1070" />
  </figure>
  <p id="zwRB"><strong>shareToAmount</strong>, в свою очередь, рассчитывает количество выдаваемых токенов. Исходя из этой формулы, становится ясным, что чем больше <strong>baseToken </strong>на аккаунте <strong>Vault </strong>и меньше <strong>totalSupply</strong>, тем больше мы получим токенов <strong>$GOV</strong>.</p>
  <figure id="JCLC" class="m_custom">
    <img src="https://img1.teletype.in/files/85/4d/854d095e-5d31-42d9-9bbd-51d24cf6e638.png" width="1070" />
  </figure>
  <p id="vodz">Вспомнив <a href="#gxSB">условия Cross-Contract Reentrancy</a> и учтя два факта выше, мы можем написать свой <s>scam</s> контракт-токен для <strong>_srcToken </strong>и использовать его при вызове функции <strong>swapAndDeposit </strong>в местах передачи потока управления для того, чтобы как можно сильнее раздуть баланс <strong>baseToken</strong> на контракте <strong>Vault </strong>и оставить <strong>totalSupply </strong>неизменным на время атаки - минтим кучу <strong>$VT</strong> (надо быть китом) и меняем по старому курсу на <strong>$GOV </strong>(лутаем миллионы). </p>
  <p id="n1KM">Вот схема того, что будет происходить во время атаки:</p>
  <figure id="HaxZ" class="m_custom">
    <img src="https://img4.teletype.in/files/f1/42/f142d376-641a-47bf-8b91-3d101e91bac5.png" width="1069.960884353742" />
  </figure>
  <h3 id="6gSz">Непосредственно атака</h3>
  <p id="A77x">Теперь посмотрим, как можно реализовать контракт-токен для атаки. Для этого мы также, как и в предыдущих контрактах должны унаследоваться от ERC20.sol.</p>
  <p id="c8nl"></p>
  <h3 id="tlN7" data-align="center">EvilERC20.sol</h3>
  <figure id="vGMH" class="m_custom">
    <img src="https://img2.teletype.in/files/51/2d/512d7eb5-91c2-4e03-b24b-b31d87941222.png" width="1070" />
    <figcaption><a href="https://gist.github.com/inspexAuditor/93e6d61d3cc4fd2cdaecf779d3799dcf#file-evilerc20-sol" target="_blank">source</a></figcaption>
  </figure>
  <p id="vxiK">При создании токена <strong>$EVIL</strong> мы передаем адреса на <strong>Vault.sol</strong>, <strong>ICOGov.so</strong>l и <strong>GovToken.sol</strong>, чтобы знать куда бить. Также в конструкторе мы минтим владельцу очень много токена <strong>$EVIL</strong> для того, чтобы он смог создать ликвидность на Uniswap перед атакой, чтоб <strong>Vault </strong>мог обменивать его на стейбл, не подозревая подвоха.</p>
  <h2 id="3Xy2">Заключение</h2>
  <p id="psNI">Таким образом, злоумышленнику для атаки требуется:</p>
  <ol id="feEW">
    <li id="FrVB">Задеплоить свой контракт токена с измененным approve</li>
    <li id="CWYj">Добавить ликвидность на пару <strong>$EVIL-baseToken </strong>на Uniswap&#x27;е</li>
    <li id="zNSs">Получить первоначальное количество токенов <strong>$VT</strong> на свой контракт</li>
    <li id="m8md">Осуществить вызов <strong>swapAndDeposit</strong></li>
  </ol>
  <p id="PIiJ">После чего можно злоумышленник может довольствоваться профитом с дополнительных процентов сверху курса обмена.</p>
  <p id="8OnO">Чтобы такое не произошло с вашим контрактом:</p>
  <ul id="Ujuu">
    <li id="2FaG">Убедитесь, что все внутренние изменения состояния выполнены до передачи потока управления - шаблон Checks-Effects-Interactions.</li>
    <li id="j7FG">Предотвращайте запуск неизвестного кода - добавьте whitelist адресов контрактов (токенов).</li>
    <li id="TwLw">Используйте блокировку повторного входа, например, <a href="https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard" target="_blank">ReentrancyGuard</a> от OpenZeppelin, но это не спасет вас от reentrancy между контрактами.</li>
  </ul>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="T9Cd">Атаку с обменом токена как в данном примере имеет смысл применять, когда токен только минтится, есть куда сбыть токен и есть весовая доля капитализации токена / активы для ее покупки.</p>
  </section>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="pTci">Случаи реальных взломов:</p>
    <p id="lXIs"><a href="https://inspexco.medium.com/value-defis-invalid-share-calculation-exploit-in-depth-analysis-1c8f97c1416e" target="_blank">Attack on ValueDefi (7 May 2021)</a></p>
    <p id="opCq"><a href="https://nipunp.medium.com/5-8-21-rari-capital-exploit-timeline-analysis-8beda31cbc1a" target="_blank">Attack on Rari Capital (8 May 2021)</a></p>
  </section>
  <h3 id="NN3M">Пишите свои замечания и пожелания в комментариях</h3>
  <p id="Jo6d">Мой канал в телеграме - <a href="https://t.me/kyo_dev" target="_blank">https://t.me/kyo_dev</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@kyoukisu/attacks_reentrancy</guid><link>https://teletype.in/@kyoukisu/attacks_reentrancy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu</link><comments>https://teletype.in/@kyoukisu/attacks_reentrancy?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu#comments</comments><dc:creator>kyoukisu</dc:creator><title>Атаки на контракт - Reentrancy</title><pubDate>Mon, 11 Jul 2022 13:58:00 GMT</pubDate><media:content medium="image" url="https://img3.teletype.in/files/e2/9c/e29c4677-b8f4-4aef-9be2-9b993a5695c4.png"></media:content><description><![CDATA[<img src="https://img3.teletype.in/files/61/db/61dbbcfd-ea0a-415a-bf44-dd5823e84ad1.jpeg"></img>Всем привет, с вами @kyoukisu (кёкису). Вкатываюсь в разработку на Solidity и меня заинтересовала тема атак на контракты. Почему? Потому что кроме написания самих контрактов как web3 разработчик будет полезно понимать, как с них могут украсть позаимствовать много денег такие уважаемые люди как tern и user221 и как этого не допустить.]]></description><content:encoded><![CDATA[
  <figure id="SWrf" class="m_custom">
    <img src="https://img3.teletype.in/files/61/db/61dbbcfd-ea0a-415a-bf44-dd5823e84ad1.jpeg" width="1090.9305210918114" />
  </figure>
  <p id="JW4c">Всем привет, с вами <a href="https://t.me/kyoukisu" target="_blank">@kyoukisu</a> (кёкису). Вкатываюсь в разработку на Solidity и меня заинтересовала тема атак на контракты. Почему? Потому что кроме написания самих контрактов как web3 разработчик будет полезно понимать, как с них могут <s>украсть</s> позаимствовать много денег <s>такие уважаемые люди как tern и user221</s> и как этого не допустить.</p>
  <p id="g9uy">По сему поводу решил начать писать+переводить цикл статей посвященных теме атак на контракты. Первая статья это разбор атаки Reentrancy, дополнительно к ней будет еще одна с более сложным более реальным примером и его полным разбором.  Данный цикл будет являться вольным переводом информации с <a href="https://consensys.github.io/smart-contract-best-practices/attacks" target="_blank">Ethereum Smart Contract Best Practices</a>.</p>
  <h2 id="McJk">Что такое Reentrancy?</h2>
  <p id="I4v7">Слово «<strong>reentrancy</strong>» означает «<strong>повторный вход</strong>». Всякий раз, когда смарт-контракт делает внешний вызов другому смарт-контракту, может быть осуществлен повторный выход в исходную функцию. Кроме того, когда смарт-контракт делает внешний вызов, выполнение EVM передается от смарт-контракта, выполняющего вызов, к тому, который вызывается.</p>
  <h2 id="yVQC">Single Function Reentrancy</h2>
  <p id="Wbf5">Первая замеченная версия этого эксплойта касалась функций, которые могли вызываться многократно и рекурсивно, до завершения первого вызова функции.</p>
  <p id="l56W">Рассмотрим следующий код:</p>
  <figure id="YFad" class="m_column">
    <img src="https://img2.teletype.in/files/db/e1/dbe11601-e13d-4886-943c-7eb734f53777.png" width="1220" />
    <figcaption>Функция вывода с уязвимостью reentrancy</figcaption>
  </figure>
  <p id="LrYh">На 8 строчке происходит перевод средств на адрес вызывающего функцию, однако если вызывающий - другой смарт-контракт, то <strong>msg.sender.call</strong> приведет к срабатыванию <strong>fallback </strong>функции на стороннем контракте.</p>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="03xg"><strong>Fallback </strong>выполняется при вызове контракта, если ни одна из других функций не соответствует заданному идентификатору функции (или если данные вообще не были предоставлены). Кроме того, эта функция выполняется всякий раз, когда контракт получает эфир без данных.</p>
  </section>
  <figure id="9247" class="m_column">
    <img src="https://img2.teletype.in/files/5e/52/5e52a0e6-5b3e-402b-89a5-533c6cf20b06.png" width="826" />
    <figcaption>receive - пример fallback функции, которая рекурсивно вывела бы все деньги с контракта</figcaption>
  </figure>
  <p id="1esV">Функция receive вызовет повторно <strong>withdrawBalance</strong> и т.к. 7 строчка еще не успела обнулить баланс пользователя <strong>userBalances[msg.sender] = 0, </strong>это позволит злоумышленнику получать рекурсивно эфир, пока баланс контракта не истощится.</p>
  <figure id="YT9Q" class="m_column">
    <img src="https://img2.teletype.in/files/19/aa/19aa7e6c-5942-49ee-96c6-1267de0ffbe3.png" width="1514" />
    <figcaption>как происходит атака</figcaption>
  </figure>
  <p id="P32U">В приведенном примере лучший способ предотвратить эту атаку - убедиться, что вы не вызываете внешнюю функцию, пока не выполните всю необходимую внутреннюю работу по изменению состояния контракта, такой шаблон называют Checks-Effects-Interactions:</p>
  <figure id="gMNP" class="m_column">
    <img src="https://img2.teletype.in/files/9e/d0/9ed024dc-553c-4811-a01e-fc1bef1a89ef.png" width="1210" />
    <figcaption>Исправленная функция вывода</figcaption>
  </figure>
  <p id="0rLl">После первого вызова баланс пользователя будет равен 0, поэтому последующие вызовы ничего не снимут.</p>
  <h2 id="el8H">Cross-Function Reentrancy</h2>
  <p id="c3Ax">Злоумышленник также может быть в состоянии выполнить аналогичную атаку, используя две различные функции, которые используют одно и то же состояние.</p>
  <p id="EzCM">Рассмотрим контракт, который хранит в себе 2 баланса для пользователя - в эфире и в каком-то токене.</p>
  <figure id="Qo1H" class="m_column">
    <img src="https://img2.teletype.in/files/15/fe/15fe7379-dfb5-40b1-8986-5da74ac16956.png" width="1143" />
  </figure>
  <p id="1x9R">В этом случае злоумышленник вызывает <strong>withdrawBalance</strong>, а внешний вызов через <strong>fallback </strong>на строке 30 вызывает <strong>exchangeAndWithdrawBalance</strong>. Поскольку баланс токена еще не установлен в 0, можно перевести токены, даже если вывод средств был осуществлен.</p>
  <p id="U6v5">Решением проблемы будет тот же способ предотвращения, что и в первом случае с одиночной функцией.</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="C0z4">Также обратите внимание, что в данном примере обе функции были частью одного контракта. Однако одна и та же ошибка может возникнуть в нескольких контрактах, если эти контракты имеют общее состояние.</p>
  </section>
  <h2 id="UbtV">Подводные камни при решении проблемы Reentrancy</h2>
  <p id="UwGZ">Поскольку <strong>reentrancy </strong>может возникать в нескольких функциях и даже в нескольких контрактах, любое решение, направленное на предотвращение <strong>reentrancy </strong>с помощью одной функции, будет недостаточным.</p>
  <p id="8wF1">Вместо этого рекомендуется сначала завершить всю внутреннюю работу (т.е. изменение состояния), и только потом вызывать внешнюю функцию. Это правило, если следовать ему тщательно, позволит вам избежать уязвимостей, связанных с <strong>reentrancy </strong>. Однако нужно не только избегать слишком раннего вызова внешних функций, но и избегать вызова функций, которые вызывают внешние, как, например, в коде ниже:</p>
  <figure id="XaCn" class="m_column">
    <img src="https://img2.teletype.in/files/d6/97/d6975d17-377c-42fd-a60a-cf0f574aa1cc.png" width="1089" />
    <figcaption>Уязвимость reentrancy в функции getFirstWithdrawalBonus</figcaption>
  </figure>
  <p id="jME4">Даже если <strong>getFirstWithdrawalBonus </strong>не вызывает напрямую внешний контракт, вызова <strong>withdrawReward</strong> будет достаточно, чтобы сделать его уязвимым для <strong>reentrancy</strong>.</p>
  <p id="wQvw">Следуя шаблону, что в первую очередь надо менять состояние контракта и только потом вызывать внешние функции - так мы сможем убрать уязвимость из примера выше.</p>
  <figure id="7jco" class="m_column">
    <img src="https://img4.teletype.in/files/39/10/3910b7b9-f53e-40c5-a6c3-509ce20b160f.png" width="716" />
  </figure>
  <p id="eE15">Теперь после первого вызова <strong>claimedBonus[recipient] = true</strong>, поэтому последующий вызов будет остановлен из-за <strong>require</strong>.</p>
  <p id="AInj">Другим часто используемым решением является <strong>мьютекс</strong>. </p>
  <h2 id="01qZ">Мьютекс</h2>
  <section style="background-color:hsl(hsl(199, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="1kT7"><strong>Мью́текс</strong> (mutex, от mutual exclusion — «взаимное исключение») — примитив синхронизации, обеспечивающий взаимное исключение исполнения критических участков кода.</p>
  </section>
  <p id="uPka">Это позволяет вам &quot;заблокировать&quot; некоторое состояние так, чтобы его мог изменить только владелец блокировки. Простой пример может выглядеть следующим образом:</p>
  <figure id="0XVP" class="m_column">
    <img src="https://img2.teletype.in/files/53/b0/53b0f956-3312-44e4-beef-eead05bd364b.png" width="1193" />
  </figure>
  <p id="R8ko">На 21 строчке проверяется был ли вызов успешен, если пользователь попытается снова вызвать <strong>withdraw</strong> до завершения первого вызова, блокировка не даст ему оказать никакого эффекта. Это может быть эффективным шаблоном, но он становится сложным, когда у вас есть несколько контрактов, которые должны сотрудничать.</p>
  <h3 id="o3xs">Пример очень тупой ошибки работы с мьютексом</h3>
  <figure id="aYGc" class="m_column">
    <img src="https://img2.teletype.in/files/d2/42/d2423cec-c651-4865-bfc3-3fe2924cbf0f.png" width="718" />
  </figure>
  <p id="AvMG">Логика контракта - пользователь может запросить доступ к средствам контракта, затем осуществить спокойно вывод, а потом снять блокировку.</p>
  <p id="QdyL">Пользователь/злоумышленник может вызвать <strong>getLock </strong>через <strong>requestWithdrawal</strong>, а затем никогда не вызывать <strong>releaseLock </strong>через <strong>finalizeWithdrawal</strong>. Если это сделать, то контракт будет заблокирован навсегда, и ничто уже не поможет. Если вы используете мьютексы для защиты от <strong>reentrancy</strong>, вам необходимо тщательно следить за тем, чтобы не было возможности осуществить блокировку и не освободить в дальнейшем.</p>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="dfpd">При работе с мьютексами можно себе прострелить ногу <a href="#SWrf">(или голову)</a>, поэтому стоит ознакомиться с такими понятиями как <a href="https://www.google.com/search?q=race+condition+%D1%87%D1%82%D0%BE+%D1%8D%D1%82%D0%BE" target="_blank">race condition</a> и <a href="https://www.google.com/search?q=deadlock+%D1%87%D1%82%D0%BE+%D1%8D%D1%82%D0%BE" target="_blank">deadlocks</a>.</p>
  </section>
  <p id="n70Y">Решением для примера выше будет не оставлять возможности пользователям контракта управлять мьютексом и после завершения работы <strong>обязательно</strong> освобождать мьютекс.</p>
  <figure id="WCF9" class="m_original">
    <img src="https://img3.teletype.in/files/a2/8d/a28dedec-38e4-4090-ad45-0f59c8b3d693.png" width="706" />
  </figure>
  <h2 id="6KbN">Заключение</h2>
  <p id="KMyH">В атаке с <strong>reentrancy </strong>вредоносный контракт обращается к вызывающему контракту до завершения первого вызова функции. Это может привести к нежелательному взаимодействию различных вызовов функции.</p>
  <p id="8OnO">Best practices, чтобы избежать <strong>reentrancy</strong>:</p>
  <ul id="Ujuu">
    <li id="2FaG">Убедитесь, что все внутренние изменения состояния выполнены до передачи потока управления - шаблон Checks-Effects-Interactions.</li>
    <li id="xtVm">Используйте блокировку повторного входа, например, <a href="https://docs.openzeppelin.com/contracts/4.x/api/security#ReentrancyGuard" target="_blank">ReentrancyGuard</a> от OpenZeppelin.</li>
  </ul>
  <section style="background-color:hsl(hsl(55,  86%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="4VVN">Если хотите попрактиковаться в поиске уязвимостей reentrancy, можете обратиться к ресурсу <a href="https://swcregistry.io/docs/SWC-107" target="_blank">SWC Registry</a>. Там есть два примера на reentrancy с решениями. Первый сложный, второй проще. Не заспойлерите себе случайно ответы.</p>
  </section>
  <section style="background-color:hsl(hsl(323, 50%, var(--autocolor-background-lightness, 95%)), 85%, 85%);">
    <p id="PHfv">Разбор реального взлома через reentrancy <a href="https://hackingdistributed.com/2016/06/18/analysis-of-the-dao-exploit/" target="_blank">The DAO</a>.</p>
  </section>
  <h3 id="NN3M">Пишите свои замечания и пожелания в комментариях</h3>
  <p id="Jo6d">Мой канал в телеграме - <a href="https://t.me/kyo_dev" target="_blank">https://t.me/kyo_dev</a></p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@kyoukisu/docker</guid><link>https://teletype.in/@kyoukisu/docker?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu</link><comments>https://teletype.in/@kyoukisu/docker?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu#comments</comments><dc:creator>kyoukisu</dc:creator><title>Docker - для чего?</title><pubDate>Sat, 21 May 2022 12:10:40 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/5b/b5/5bb54fb0-b923-4346-a116-761550b3ce4f.png"></media:content><description><![CDATA[<img src="https://habrastorage.org/webt/b7/dj/ot/b7djotv_rf_w4fh7wxkpeykxj6g.jpeg"></img>Докер нужен для создания изолированных контейнеров, в которых вы можете кодить и творить что хотите, а потом делиться ими. Можно запустить на нем свой мини-линукс, который потом легко интегрируется со многими IDE. Собрали код для абуза с кучей сложных зависимостей в контейнере, сделали коммит в образ, поделились образом с другом, друг без ебли установил образ в своем докере и пользуется вашими наработками без необходимости самому что-то настраивать.]]></description><content:encoded><![CDATA[
  <figure id="EMHA" class="m_column">
    <img src="https://habrastorage.org/webt/b7/dj/ot/b7djotv_rf_w4fh7wxkpeykxj6g.jpeg" width="3186" />
  </figure>
  <p id="FqUm">Докер нужен для создания изолированных контейнеров, в которых вы можете кодить и творить что хотите, а потом делиться ими. Можно запустить на нем свой мини-линукс, который потом легко интегрируется со многими IDE. Собрали код для абуза с кучей сложных зависимостей в контейнере, сделали коммит в образ, поделились образом с другом, друг без ебли установил образ в своем докере и пользуется вашими наработками без необходимости самому что-то настраивать.</p>
  <h2 id="gTmO">Установка</h2>
  <p id="VGzU">Качаете установщик отсюда:<br /><a href="https://docs.docker.com/desktop/windows/install/" target="_blank">https://docs.docker.com/desktop/windows/install/</a><br />(и следуете процессу установки, если вы знаете английский)</p>
  <p id="AiHZ">No-brain жмете вперед, попросит перезагрузиться. Во время перезагрузки включаем <a href="https://www.google.com/search?q=%D0%BA%D0%B0%D0%BA+%D0%B2%D0%BA%D0%BB%D1%8E%D1%87%D0%B8%D1%82%D1%8C+%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8E+%D0%B2+bios+gigabyte+amd" target="_blank">в биосе виртуализацию </a>если она не включена, как ее включить - вбейте в гугл свою материнскую плату и &quot;how to turn on virtualization&quot; и ищите видос. Проверить включена ли она можно в диспетчере задач:</p>
  <figure id="DZT3" class="m_column">
    <img src="https://i.imgur.com/mdo6T8z.png" width="895" />
  </figure>
  <p id="4G0p">После перезагрузки docker скажет вам ошибку, что надо установить еще WSL (Windows Subsystem for Linux - слой совместимости для запуска Linux-приложений), качаете, ставите:<br /><a href="https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package" target="_blank">https://docs.microsoft.com/en-us/windows/wsl/install-manual#step-4---download-the-linux-kernel-update-package</a></p>
  <p id="A6UJ">Если все сделано правильно, то вас встретит такой интерфейс:</p>
  <figure id="GXKU" class="m_column">
    <img src="https://img2.teletype.in/files/db/49/db494c65-018c-460e-9f91-ef9dbb86c26c.png" width="1007" />
    <figcaption>не мой скрин, поэтому шакалы покусали</figcaption>
  </figure>
  <p id="oX34">Идем качать наши образы:</p>
  <p id="qRKC"><a href="https://hub.docker.com/search?q=ubuntu" target="_blank">https://hub.docker.com/search?q=ubuntu</a></p>
  <figure id="GMiP" class="m_column">
    <img src="https://img4.teletype.in/files/3e/a9/3ea9362a-bf84-4e02-9f20-6f786eabdb75.png" width="1289" />
  </figure>
  <p id="Vzbo">Можете выбрать образ под определенный язык программирования, где уже будет все установлено для его использования, я обычно выбираю чистую убунту, куда сам всё ставлю.</p>
  <p id="GZaU">После выбора образа копируете команду, которая справа:</p>
  <figure id="Ewdb" class="m_column">
    <img src="https://img2.teletype.in/files/53/b0/53b059c0-7f69-405f-b25b-d933348a5252.png" width="1292" />
    <figcaption>в данном случае docker pull ubuntu</figcaption>
  </figure>
  <p id="y5CB">Ее прописываете в консоли, не забыв запустить docker перед этим. После чего в самом приложении докера во вкладке Images вы увидите ваш образ:</p>
  <figure id="yqXh" class="m_original">
    <img src="https://img1.teletype.in/files/0f/cb/0fcb8b1c-3ad2-4328-b60d-8eaa0b4b3393.png" width="1112" />
  </figure>
  <p id="6JJQ">Наводитесь на него и жмете RUN:<br /></p>
  <figure id="pv6Y" class="m_column">
    <img src="https://img3.teletype.in/files/67/c8/67c8b2fb-fc69-4b10-b4ab-62cdc949bf57.png" width="558" />
  </figure>
  <p id="096G">Здесь указываете имя контейнера, а можете не указывать и докер сам даст какое-нибудь забавное имя.</p>
  <figure id="VkX4" class="m_original">
    <img src="https://img3.teletype.in/files/69/e9/69e9f15c-acd1-4920-8e32-a9da120d757b.png" width="1119" />
  </figure>
  <p id="wOgX">После этого у вас во вкладке Containers появится ваш контейнер/виртуалка, которую можно включать, выключать, использовать. Нажав на первую кнопку CLI, видим следующее:<br /></p>
  <figure id="IyUk" class="m_original">
    <img src="https://img4.teletype.in/files/79/ca/79ca3f6d-f4a5-48d7-8c9b-54946c3d5055.png" width="523" />
  </figure>
  <p id="Jsus">Пишем туда это:</p>
  <pre id="NcTg"> /bin/bash</pre>
  <figure id="UEpv" class="m_original">
    <img src="https://img3.teletype.in/files/23/4e/234e4674-d5cd-40dc-8b65-c29d7b4a249e.png" width="525" />
  </figure>
  <p id="7MM5">Наш линукс готов!</p>
  <p id="b4T8">Пакеты устанавливать можно через apt install, например, установка питона:</p>
  <pre id="Xm5C">apt update
apt install python</pre>
  <p id="lu5f">Первая команда нужна при первом запуске, чтобы обновить репозитории на машине, чтоб она знала сама откуда что качать.<br /></p>
  <figure id="ia3E" class="m_original">
    <img src="https://img4.teletype.in/files/3b/d3/3bd38b78-1c22-4256-8ee5-f0a819490f20.png" width="527" />
  </figure>
  <p id="ZXcM">При установке будет просить нажать Y и enter. Если уверены в себе, можете добавлять флаг -y, чтобы не просило:</p>
  <figure id="T1Ri" class="m_original">
    <img src="https://img2.teletype.in/files/d5/bf/d5bff0c8-bd34-4e5e-a40f-eb0c1b8009fe.png" width="355" />
  </figure>
  <p id="BQEM">После чего питон установлен:</p>
  <figure id="vO8i" class="m_original">
    <img src="https://img1.teletype.in/files/c3/73/c3734d76-949f-4c42-8936-1494dd588092.png" width="514" />
  </figure>
  <h2 id="e6fB">Интеграция с VSCode</h2>
  <p id="ceWY">Устанавливаем расширение:<br /><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers" target="_blank">https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers</a></p>
  <p id="w3xf">В vscode жмем сочетание клавиш ctrl+shift+p, печатаем attach:</p>
  <figure id="k3aS" class="m_original">
    <img src="https://img4.teletype.in/files/31/99/3199af8b-fdee-4df8-ba32-019ae9fc0568.png" width="599" />
  </figure>
  <p id="TfxY">Если ваш контейнер запущен, то его можно будет выбрать:</p>
  <figure id="YNv6" class="m_original">
    <img src="https://img3.teletype.in/files/6d/b5/6db5ba2d-052e-4dd2-9400-9bd314d2b6f8.png" width="612" />
  </figure>
  <figure id="EKpH" class="m_column">
    <img src="https://img1.teletype.in/files/c3/ee/c3ee7487-2ae4-4147-9c94-f1ce1ebaaa26.png" width="1022" />
  </figure>
  <p id="y1Pg">Теперь вы можете разрабатывать код в изолированном контейнере. Открыв консоль в VSCode, можно удостовериться, что вы используете не исходную машину, а контейнер.</p>
  <figure id="pixF" class="m_original">
    <img src="https://img1.teletype.in/files/01/ed/01edb11d-c3ed-479e-a06e-2748907203b7.png" width="678" />
  </figure>
  <p id="saWw">Быстро переподкличаться к прошлому workspace можно вот так:</p>
  <figure id="NBF5" class="m_column">
    <img src="https://img4.teletype.in/files/39/cb/39cb97bb-fc07-460f-a7dc-494c0a599286.png" width="826" />
  </figure>
  <p id="86QK">Менять корневую папку в VSCode можно через ctrl+o:</p>
  <figure id="QVM0" class="m_original">
    <img src="https://img2.teletype.in/files/53/87/538773ca-beb0-4f88-b257-663026685c62.png" width="601" />
  </figure>
  <h2 id="RpbW">Заключение</h2>
  <p id="xSIK">Docker - это круто, модно, молодежно и удобно. Основным мотивом начать использовать докер для меня стала новость о прикольном изменении библиотеки node-ipc, которая использовалась во многих популярных и крупных библиотеках для nodejs, под ударом оказался даже софт для разработки игр Unity, а именно их Hub. Библиотека затирала все ваши файлы, если ваш ip из России или Беларуси. Подробнее о ней - <a href="https://www.youtube.com/watch?v=i2fsOjJrN6w" target="_blank">https://www.youtube.com/watch?v=i2fsOjJrN6w</a>. Если бы вы просто установили одну из либ для nodejs, которая была зависима от node-ipc, то вашему компу пришел бы кирдык, после запуска проекта, поэтому безопасность во время разработки необходимо тоже соблюдать.</p>

]]></content:encoded></item><item><guid isPermaLink="true">https://teletype.in/@kyoukisu/regex</guid><link>https://teletype.in/@kyoukisu/regex?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu</link><comments>https://teletype.in/@kyoukisu/regex?utm_source=teletype&amp;utm_medium=feed_rss&amp;utm_campaign=kyoukisu#comments</comments><dc:creator>kyoukisu</dc:creator><title>Regex – что это и нафиг надо?</title><pubDate>Thu, 21 Apr 2022 13:22:56 GMT</pubDate><media:content medium="image" url="https://img2.teletype.in/files/de/48/de48577e-c990-4c80-acad-739f7f22329f.png"></media:content><description><![CDATA[<img src="https://miro.medium.com/max/1400/1*FqgpJTpg_ti1P4k4B48CJw.jpeg"></img>Каждый явно сталкивался с кучей данных в текстовом формате при покупке аккаунтов или обработке логов. Если хочется засунуть данные в таблицы Excel, то надо данные так представить, чтобы прокси запихать в программу – иначе. Регулярные выражения (далее регулярки, regex) позволяют находить заданные паттерны в тексте, их поддержка есть во многих редакторах кода, в notepad++, notepad их нет :(]]></description><content:encoded><![CDATA[
  <figure id="NaZH" class="m_column">
    <img src="https://miro.medium.com/max/1400/1*FqgpJTpg_ti1P4k4B48CJw.jpeg" width="1242" />
  </figure>
  <p id="VrPO">Каждый явно сталкивался с кучей данных в текстовом формате при покупке аккаунтов или обработке логов. Если хочется засунуть данные в таблицы Excel, то надо данные так представить, чтобы прокси запихать в программу – иначе. Регулярные выражения (далее регулярки, regex) позволяют находить заданные паттерны в тексте, их поддержка есть во многих редакторах кода, в notepad++, notepad их нет :(</p>
  <h2 id="hpc1">К делу.</h2>
  <p id="7Zk1">Есть много вариантов использования regex, я решил показать пару вариантов, которые использую я “в быту”, чтобы вас как-то заинтересовать. Есть много статей, посвященных регулярным выражениям, если вам лень писать что-то свое, изучать, хочется быстро узнать ответ – вбиваем в гугл фразу “regex how to” и свой вопрос кратко, да, желательно на английском.</p>
  <p id="dIjl">Базовые вещи, которые пригодятся (можете поверхностно прочитать):</p>
  <pre id="9iX9">.* - любое количество любых символов
\d – цифра
\D – не цифра
\s – пробельный символ
\S – не пробельный символ
\w – буквенный символ или нижнее подчеркивание
\W – не то, что в статье строкой выше
\n – разрыв строки
(abcde) – группировка символов (как в математике)
(abcde)? – ноль или одно повторение конструкции abcde
(abcde)* - ноль или более
(abcde)+ – одно или более</pre>
  <h3 id="h8TQ">Пример 1. Аккаунты в Excel.</h3>
  <p id="4ge1">Например, купили мы почты (штук 50+) на какой-то площадке ОТС, accsmarket и т.п. и хотим их без гемора поместить в excel табличку со своими аккаунтами. Для того открываем <s>самый большой чат кодеров и умоляем помочь вам</s> VSCode, Sublime Text 3 или что-то еще и вставляем аккаунты:</p>
  <figure id="aTh3" class="m_column">
    <img src="https://img1.teletype.in/files/03/23/032364a9-1296-448f-b8cb-f5a0610ddd70.png" width="253" />
  </figure>
  <p id="fmEX">Основным инструментом будет поиск с заменой, открывается в большинстве редакторов сочетанием клавиш CTRL+H. На примере VSCode в появившемся окошке жмем стрелку вниз и получаем такое меню:</p>
  <figure id="gg1h" class="m_column">
    <img src="https://img4.teletype.in/files/75/57/755783d3-8b43-4980-8428-6eb2cd8ad60e.png" width="666" />
  </figure>
  <p id="hqOM">Первая строчка отвечает за поиск паттерна, вторая за его замену на что-то.</p>
  <p id="sWJS">Первая кнопка в строке поиска обозначает поиск игнорируя регистр букв, вторая поиск строго словами, третья — использование регулярных выражений, <strong>нажимаем ее</strong>.</p>
  <p id="LylO">Вообще, мелочей много, но они быстро запоминаются, если начинаешь работать с этим, считайте это языком программирования, но только для обработки текста. Многие языки программирования имеют поддержку regex, чтобы использовать это в вашей программе для поиска чего-нибудь в текстах.</p>
  <p id="wqbb">Взглянув на наши аккаунты, можем заметить, что почты и пароли чередуются, причем иногда пароли имеют приписку password: или pass:. Руками явно не захочется обрабатывать кучи строк кода, да еще и ошибиться где-то случайно, потенциально потеряв аккаунт в будущем.</p>
  <p id="OGP7">Явно можно выделить факт, что приписки password: и pass: начинаются с pas и заканчиваются на двоеточие.<br />Строки с паролями стоят под почтами, что нам позволяет их отличить, поэтому стереть лишнюю информацию по обозначению пароля. Регулярное выражение pas.*: выбирает любые цепочки символов, которые начинаются с pas, а заканчиваются на двоеточие. Заносим его в первую строку окошка, вторую оставляем пустой, жмем заменить все:</p>
  <figure id="DvN9" class="m_column">
    <img src="https://img2.teletype.in/files/9b/b9/9bb9f164-80c4-4d34-9d00-45b2c6f3d42c.png" width="975" />
  </figure>
  <p id="EsMc">После этого у нас пропадают все не нужные приписки к паролю:</p>
  <figure id="3by5" class="m_column">
    <img src="https://img3.teletype.in/files/a6/59/a6594578-1ccb-4f85-9e29-7bf7f0448613.png" width="975" />
  </figure>
  <p id="Vz0J">Теперь мы хотим наши данные привести к виду почта:пароль, чтобы занести их в таблицу Excel или какие-то конфиги для софта. Для этого (без усложнений сложными регулярками) заменяем конец почты com и символ разрыва строки на com и двоеточие. Т.е. мы прилепим к почтам, которые заканчиваются на com, через двоеточие пароли.</p>
  <figure id="GMyz" class="m_column">
    <img src="https://img4.teletype.in/files/7b/e3/7be3fce6-fd7a-41dc-b0c9-84fb45bb60f5.png" width="975" />
  </figure>
  <figure id="UtQA" class="m_column">
    <img src="https://img3.teletype.in/files/a7/9a/a79abab9-75be-4da4-9dc0-304f33baecf5.png" width="975" />
  </figure>
  <p id="qxR3">Далее берем эти данные и куда надо вставляем. В Excel’е это делается так:</p>
  <figure id="KadN" class="m_column">
    <img src="https://img2.teletype.in/files/11/0e/110e5d96-4045-4ea4-a310-2f3539364a5a.png" width="820" />
  </figure>
  <p id="9Bml">Вставка ^</p>
  <p id="6aTQ">Не убирая выделение, в поиске пишем “таблицу” или “table” и выбираем конвертацию в таблицу:</p>
  <figure id="sdmT" class="m_column">
    <img src="https://img3.teletype.in/files/ae/d6/aed6209b-e0f9-443f-920e-0a565585a519.png" width="711" />
  </figure>
  <p id="4hUp">Жмем далее:</p>
  <figure id="2mcT" class="m_column">
    <img src="https://img1.teletype.in/files/cc/7f/cc7f0dfe-4bb7-4b59-96c7-1d83f8478659.png" width="786" />
  </figure>
  <p id="BQX8">Выбираем “другое”, если нашего символа в списке нет и печатаем свой разделитель. В превью будет видно как разделяются данные:</p>
  <figure id="DVKC" class="m_column">
    <img src="https://img2.teletype.in/files/97/de/97de8e11-9f78-40fa-ac2d-56e4659f38fe.png" width="794" />
  </figure>
  <p id="9dE1">Жмем далее, завершить.</p>
  <figure id="X9GW" class="m_column">
    <img src="https://img4.teletype.in/files/71/13/7113bf8e-029f-43f1-9e87-6764919e1a1d.png" width="322" />
  </figure>
  <p id="w4Be">Получаем данные в двух столбцах.</p>
  <h3 id="iv9n">Пример 2. Аккаунты в Python.</h3>
  <p id="bXNo">Допустим теперь мы хотим эти аккаунты задействовать у нас в коде, но без парсинга файла. Отформатируем их в виде массива. Для этого используем тот факт, что они уже записаны через двоеточие, будем представлять каждый аккаунт как массив из двух элементов - логина и пароля. Берем 2 конструкции (.*), которые находятся с двух сторон от двоеточия (.*):(.*)</p>
  <figure id="aiEm" class="m_column">
    <img src="https://img3.teletype.in/files/20/a5/20a5f3ad-05a3-4146-9bc2-dfbb3db2189f.png" width="688" />
  </figure>
  <p id="w5O1">Теперь сделаем, чтобы первая и вторая группы после замены лежали в массиве, добавим кавычки и запятую в конце [&#x27;$1&#x27;,&#x27;$2&#x27;],</p>
  <figure id="bMgW" class="m_column">
    <img src="https://img2.teletype.in/files/14/d7/14d76c6b-2a13-407b-bffc-0a1d8065f29e.png" width="675" />
  </figure>
  <p id="odTs">Далее просто добавляем в начале и в конце еще одни квадратные скобки, удаляем разрывы строк \n и присваиваем это переменной.</p>
  <figure id="JIcl" class="m_column">
    <img src="https://img3.teletype.in/files/2e/a8/2ea8744d-f19a-431f-8f32-692eb37a8ed1.png" width="657" />
  </figure>
  <figure id="dvLB" class="m_column">
    <img src="https://img1.teletype.in/files/8d/68/8d68160e-bb62-4ce0-a3ee-a45495f14f69.png" width="647" />
  </figure>
  <p id="ba8K">Теперь это можно вставлять в код и использовать (но лучше выносить все в файлы конфига, чтобы потом не приходилось вырезать все важные данные из кода).</p>
  <h3 id="nZsQ">Пример 3. Разное.</h3>
  <p id="QOim">Выделение чего угодно между одинарными кавычками &#x27;(.*?)&#x27;</p>
  <figure id="mFWE" class="m_column">
    <img src="https://img1.teletype.in/files/8e/9e/8e9e0973-f921-4842-b668-e9464dffc56a.png" width="783" />
  </figure>
  <p id="O2H0">Очистка пустых строк \n\n заменяем на \n и жмем замену пару раз</p>
  <figure id="Wcne" class="m_column">
    <img src="https://img2.teletype.in/files/9c/31/9c31e2bd-88ea-4e5c-b5ea-8b67c27a6079.png" width="788" />
  </figure>
  <h2 id="lGKN">Заключение</h2>
  <p id="7nk9">Регулярки можно использовать, как и в обработке текста вами, так и заставлять код делать за вас всю работу. Вариантов использования - море, особенно если вы программист.</p>
  <h2 id="bznE">Полезные ссылки</h2>
  <p id="AJ0X"><a href="https://regex101.com/" target="_blank">https://regex101.com/</a> потыкать регулярки онлайн</p>
  <p id="IbwH"><a href="https://habr.com/ru/post/545150/" target="_blank">https://habr.com/ru/post/545150/</a> хороший (наверно) гайд</p>
  <p id="bMZR"><a href="https://regexlib.com/" target="_blank">https://regexlib.com/</a> различные регулярки по ключевым словам</p>
  <p id="rZ6v"><a href="https://www.google.com/" target="_blank">https://www.google.com/</a> ваш лучший друг во всем</p>

]]></content:encoded></item></channel></rss>