#Ryle - Server-Side Template Injections

1 messages Β· Page 1 of 1 (latest)

dry olive
#

Yea this is basically the JS version of SQL Injection

#

You're turning the user's input, into executed code

frail vine
#

man i dont use SQL

frail vine
dry olive
#

I know, it's just what I know

#

For SQL it can be SUPER BAD

#

Because you can do like:

SELECT * FROM <user input>
#

and the user's input is:

Customer; DROP TABLE Customer;
#

So you end up with 2 statements:

SELECT * FROM Customer;
DROP TABLE Customer; // AHHHHHHHHH!
frail vine
#

no idea what any of that is about

dry olive
#

World of Databases

#

So yea, don't do JS stuff like that

#

If the user gives a string, only ever have it a string.
Don't run it as code, or HTML, etc

frail vine
#

so would a fix be, to check if the string is a command or something?

#

then to just return if it was anything that wasnt a command?

vagrant ermine
#

I'm feeling like getting lectured by Yinoguns sensei xD

vagrant ermine
dry olive
vagrant ermine
frail vine
#

same here

dry olive
#

So can you explain what the original intent was?

vagrant ermine
#

wdm?

#

why I code?

#

The vulnerable code?

dry olive
#

No the issue Ryle had

#

Or what they wanted to solve

frail vine
#

basically i was asking for an explanation for some code someone helped me with. then Airgeddon saw the vulnerability

#

i still dont see where the template injection could be in the code to be honest

vagrant ermine
#

Oh, he was confused of what the require("./handeler/"+handele+".js")(client) in his code he copied was, so I explained it to him, and he still doesn't know what the code does, so I asked him to get the handle's js source code, so I can read it and explain it for him, and it happens to be handel that executes command from the user's message.

frail vine
#

it doesnt, though

dry olive
#

ah I see, yea doesn't sound good.

#

Feel free to DM me that 2nd code so I can understand

frail vine
#

the handler file is just defining all of the commands

#

ok

vagrant ermine
#

you can still inject the code at any point though...

frail vine
#

i dont see where. im not taking any user input

dry olive
#

Yea neither do I

vagrant ermine
#

the command is the user input

#

isn't it?

frail vine
#

no

#

there is 0 user input

dry olive
#

He's shared me:

...
module.exports = (client) => {
    readdirSync("./Commands/").forEach(dir => {
...
#

And it's a handler of commands, not a command itself

frail vine
#

heres an example of what my handler.js file is pulling.

#
module.exports = {
    name: "add",
    aliases: ["create"],
    description: "Add a date to the credits command. FORMAT: `yyyy-mm-dd`.",
    run: async (client, interaction, args) => {```
vagrant ermine
#

That's not the full code?

frail vine
vagrant ermine
#

oh ok

#

so it loads, all the commands into the memory, and does nothing?

frail vine
#
        for (let file of commands) {
``` i believe this runs once for every file in commands
dry olive
frail vine
#

Here is where im running the commands themselves. this is my code:

client.on('messageCreate', async (message) => {

    if (message.author.id !== '406880301449478144') return;

    const args = message.content.slice(prefix.length).trim().split(/ +/g);
    const cmd = args.shift().toLowerCase();

    if (cmd.length === 0) return;

    let command = '';
    let aliasCheck = client.aliases.get(cmd);

    aliasCheck ? command = client.commands.get(aliasCheck) : command = client.commands.get(cmd)
    // If aliasCheck is true, the first statement will run. If it is false, the second will run.

    if (!message.content.startsWith(prefix) || message.author.bot) return;

    if (command) {
...
vagrant ermine
#

Maybe you can chain the command?

#

let me see...

frail vine
#

at the end of if (command) {...

I use: command.run(client, message, args)

#

which only runs if the "command" is one of these

#

add, creditsd, help, ping, website, or any of the aliases to those commands

#

as far as user inputs go for all of those commands, all i do is take the user input and save it to a json file

#

and i do that with just a simple messageCollector.

const dateCollector = interaction.channel.createMessageCollector({
            filter,
            time: 15000,
            max: 1
        });
``` so i think im safe?
#

i watched the video, no where in my code anywhere am i executing user input

dry olive
#

Yea, long as you're not running eval or anything, even if they write console.log(env) in their input, it'll just be saved as "console.log(env)" (a string)

frail vine
#

even if they write console.log(env) in their input, it'll just be saved as "console.log(env)" (a string)
can you explain this a bit more

vagrant ermine
#

I think it's safe becuase it's not using any eval and it checks the user id

frail vine
dry olive
#

No different than 123 while it "looks" like a number, being considered text

frail vine
#

i dont know what console.log(env) is

#

oh wait

#

im stupid

#

yea i get what youre saying

vagrant ermine
frail vine
#

i'll give you all of my index.js code if you wanna check OMEGALUL

#
client.on('messageCreate', async (message) => {

    if (message.author.id !== '406880301449478144') return;

    const args = message.content.slice(prefix.length).trim().split(/ +/g);
    const cmd = args.shift().toLowerCase();

    if (cmd.length === 0) return;

    let command = '';
    let aliasCheck = client.aliases.get(cmd);

    aliasCheck ? command = client.commands.get(aliasCheck) : command = client.commands.get(cmd)
    // If aliasCheck is true, the first statement will run. If it is false, the second will run.

    if (!message.content.startsWith(prefix) || message.author.bot) return;

    if (command) {

        /*let today = new Date()

        let currentHoursMilitary = today.getHours()
        let suffix = currentHoursMilitary >= 12 ? "PM" : "AM";

        let currentHours = ((currentHoursMilitary + 11) % 12 + 1)


        let currentMinutes = today.getMinutes()


        if (currentMinutes.toString().length === 1) {
            let currentMinutesSingle = "0" + currentMinutes

            // Hours are over 12, so it's been subtracted. Minute length is 1 character.
            console.log(`[${currentHours}:${currentMinutesSingle} ${suffix}] ${message.author.tag} ran: ${prefix}${cmd}`)
        } else {

            // Hours are over 12, so it's been subtracted. Minute length is 2 characters.
            console.log(`[${currentHours}:${currentMinutes} ${suffix}] ${message.author.tag} ran: ${prefix}${cmd}.`)
        }*/
        command.run(client, message, args)
    }




});```
#

thats the only messageCreate event i have

#

and half of that is just a clock

#

or more specifically just logging the time

dry olive
#

All that is fine βœ…

frail vine
#

and if in a command im getting user input, but using a messagecollector, thats fine too?

vagrant ermine
#

I sorry for all the ruckus I caused. I misunderstood the code. I'm a bad coder.

frail vine
#

ended up being good for me. i knew that a user having access to eval was bad but didnt know it could be done in many other ways

#

thanks for ur guys help and concern too

vagrant ermine
#

Awww thanks! ❀️

frail vine
#

yea

#

well i almost sharted my pants, though. only downside

#

ive used this code with BIG bots before. had me rethinking how lucky ive been over the past year or so

#

well not huge, but like big enough to where there was probably one bad person in the bunch

dry olive
#

Code is a complex beast, long as you're willing to learn and listen, you'll do fine.

frail vine
#

yea been trying to learn. honestly i kind of took the stupid route and learned JS and discordjs at the same time. so when it comes to parameters and stuff like that sometimes i cant fully grasp it

#
if (array.some(word => testString.includes(word))) {
``` basic example, i dont get what `word` actually is. like i know its gonna end up being every value in the array i think
#

actually, this entire thing started because i didnt understand a function

vagrant ermine
#

and clean

dry olive
frail vine
#

"this" being checking to see if the string includes it?

vagrant ermine
#

yes

dry olive
#

e.g:
[1, 2, 3, 4, 5].filter(val => val > 2)
That just gets each value greater than 2, where val is each value from the Array

frail vine
#

so the filter will run 5 times, each time val will be something different

#

so in essence...

#
if (array.some(word => testString.includes(word))) {
 
}
for (let i = 0; i < array.length; i++) {

    console.log(array[i])
    if (testString.includes(array[i])) {
        console.log(true)
    }
}
``` are these two one and the same?
dry olive
#

Sorta yea.
The "callback function" will run "per item"
5 items, 5 runs.

#

filter is just useful because you can use it instead of:

const myArray = [1, 2, 3, 4, 5];
let newArray = [];
for (let i = i; i < myArray.length; i++) {
  if (myArray[i] > 2) {
    newArray.push(myArray[i]);
  }
}
frail vine
dry olive
#

Indeed

frail vine
#

[3, 4, 5]

dry olive
frail vine
#

oh okay. interesting.

#

can you only use callbacks on arrays?

dry olive
#

Some Array functions, do edit the original, JS is a funky bastard πŸ˜„

dry olive
frail vine
#

oh god that was the answer i was not hoping for

dry olive
#

It's just a concept of code, a function for a job

frail vine
#

things just got more complicatd

vagrant ermine
vagrant ermine
#

the functional prototype

frail vine
#

so the .some()

#

also, i can see a downside of using the .some() being that it stops once its true

vagrant ermine
dry olive
#

You don't have to worry about function X over function Y for speed.

#

JS is still stupid fast, you'll lose fractions of MS if at all

frail vine
#

because the for loop will run as many times as it has to

#

but .some() stops

dry olive
#

Just depends on the job you need it to do

frail vine
#

if (array.some(word => testString.includes(word))) { if i wanted this to NOT stop once it was true, and run for every single object in the array, what function would i need to use?

dry olive
#

It's in an if so you're wanting to do something if any are true

#

So you might need to refactor; what's the purpose of the if?

frail vine
#

thats true. but if it were something like a filter and i wanted to point out to the user every word they said that was flagged, i would want it to keep running

#
for (let i = 0; i < array.length; i++) {

    console.log(array[i])
    if (testString.includes(array[i])) {
        console.log(true)
    }
}

console.log('---------------------------------')

array.forEach(word => {

    if (testString.includes(word)) {
        console.log('Flagged')
    }
})
``` and both of these seem to do the job. but theyre kind of big
dry olive
#

ah, so you probably want .map followed with a .join

#

My suggestion here, is not to code it into your bot, but to use your chrome debugger

#

hit F12 in your browser

frail vine
#

yea a console opens up

#

also im not coding this into my bot

#

this is a separate js file

dry olive
#
['Hello', 'World', 'How', 'Are', 'You?']
  .filter(word => word.includes('e'))
  .map(word => `Flagged: ${word} (contained 'e')`)

// Result:
[
  "Flagged: Hello (contained 'e')",
  "Flagged: Are (contained 'e')"
]
vagrant ermine
dry olive
vagrant ermine
frail vine
dry olive
# vagrant ermine Never
['Hello', 'World', 'How', 'Are', 'You?']
  .reduce((ac, word) => {
    if (word.includes('e')) {
      ac.push(`Flagged: ${word} (contained 'e')`);
    }
    return ac;
  }, []);

All in 1

dry olive
frail vine
vagrant ermine
dry olive
#

Reduce allows you to build something as you use it, so e.g. if you want to add a bunch of numbers together:

[1, 2, 3, 4, 5].reduce((total, val) => {
  return total + val;
}, 0);
frail vine
#

so total would be 2, and val is 1?

#

or vice versa

frail vine
dry olive
#

So the callback runs on each value:

Run 1: total = 0, val = 1 : 0 + 1 = 1
Run 2: total = 1, val = 2 : 1 + 2 = 3
Run 3: total = 3, val = 3 : 3 + 3 = 6
Run 4 total = 6, val = 4 : 6 + 4 = 10
Run 5: total = 10, val = 5 : 10 + 5 = 15

dry olive
frail vine
dry olive
#

reduce takes 2 args, a callback function, and a starting value.

frail vine
#

ah

dry olive
#

But that value can be whatever you like: 0, {}, [], new Date(), etc

dry olive
# frail vine

Must be an problem with the JS file, just use web browser debugger

vagrant ermine
#

One liner?

#

['Hello', 'World', 'How', 'Are', 'You?'].reduce((ac, word)=>{word.includes('e')?ac.push(Flagged: ${word} (contained 'e')):0;return ac;}, []);

dry olive
vagrant ermine
dry olive
#

It took me a while to understand reduce because the first time I saw it was a crazy one by my collegue, eventually something clicked, now I use them alot πŸ˜„

frail vine
#

yea dont see myself using that a lot

#

ill stick to filter and map

#

cuz map just runs once for every object in an array right?

vagrant ermine
frail vine
#

facts

#

i came to the chat to maybe learn a little from someone getting help or to help someone, and i just got lectured

#

(in a good way)

dry olive
#

I spend a good bit of time helping a collegue who is new to coding, so I've learnt some good ways to explain things.

#

Never feel bad for not knowing something, and always feel good about learning.

frail vine
#

yea

frail vine
#

im honestly interested in getting a job in this industry, but im a junior in high school and im taking algebra 2 this year. feel like im kinda behind

frail vine
frail vine
#

but ive heard that the industry of programming is HEAVILY competitive right now so you like NEED a comp sci degree to even get anywhere

#

and tbh, my coding skills dont go much further than basic js programs and discord bots. dont know where to start to make meaningful things

dry olive
#

When I went to University, I did Computer Science, I learnt a lot ,but it no way fully prepared me for an actual Job, you learn SOOOO much more.

So focus on learning code, and learning practices.

I will take someone who knows good code, practices, and isn't a shithead, over a know-it-all who is actually bad at writing code or problem solving.

frail vine
#

Why yes that is true, are you sure you dont need a degree to even get started?

dry olive
#

My suggestion to you for now, is keep with Discord Bots.
You understand them, and can be enthuastic about them.

Just keep pushing the boundry, work on Slash Commands, then Buttons, then Menus, throw a Database in there, make a Currency System.

PUSH YOURSELF - and keep it fun, and just learn.
Make a Portfolio win!

frail vine
dry olive
frail vine
dry olive
#
  • it has a DB
frail vine
#

with no strings attached? no free trial that ends?

#

AWS bit me in the butt after 12 months

dry olive
#

Nope, long as you're not making something for Commercial Earnings

#

I use AWS professionally at work, and I looked into it, but yea screw their costs

frail vine
#

im assuming theres a threshold on your bitrate and storage usage though?

vagrant ermine
dry olive
frail vine
dry olive
#

and the Database is I think 1GB or something, even if it's less it's more than I need

dry olive
frail vine
#

because i have a bot that uses the presenceUpdate event, which can be heavy on bitrate i believe because presences change so often

#

basically, presence changes, it gives you a role depending on presence

#

(specifically streaming/listening to spotify)

vagrant ermine
frail vine
#

Anyways, could you give me the name of the platform? I'd way rather my bot crash because of a limit than have the platform keep silent then just charge me out of nowhere

#

cuz that was a big thing that discouraged me...

dry olive
#

Sent

#

There is one caveat

#

You get "free hours" but these hours are not enough for a whole month...unless, you register a payment card; then you get enough for 1 bot process to run round the clock.

#

It's not cost, it's just you register the card and you're gold

#

@frail vine

frail vine
#

so if i dont register the card, i just have to deal with not being able to host my bot 24/7

#

and do these free hours replenish at the start of each month

dry olive
#

Correct

#

I think it's like 500yrs

frail vine
#

yrs OMEGALUL

dry olive
#

So enough for like 20d of uptime

#

haha, hrs*

#

But add the card, that's 40d and still free.

frail vine
#

so do i gotta publish my bot to github to use heroku?

dry olive
#

There's some options I think, but GH is the one I use.

#

You can set an alt-remote too

vagrant ermine
dry olive
#

ah, atm GH pushing is broke due to a security issue, let me find the link

frail vine
#

nah, i know github to an extent ill use that

#

oh shoot

#

Only question is, will the bot still be able to write data to a json file or am i gonna have to learn how to use MongoDB

vagrant ermine
dry olive
frail vine
vagrant ermine
dry olive
frail vine
#

not familiar with what a local repo is

dry olive
#

Just the thing on your machine

frail vine
#

so cmd prompt?

dry olive
#

Wait local repo, huh

frail vine
#

From the local repository's root directory, enter these commands:

dry olive
#

ah do the folder of your project

frail vine
#

so just go into my cmd prompt and go into my folder of the project then start doing this commands?

dry olive
#

Or through your IDE, either works

#

You'll need a Heroku account first and all that.

dry olive
#

There will be some effort in getting it setup

#

I think writing files might use up the Memory space, or even not be possible.

#

Are you using the files to track data?

frail vine
#

yea

#

here

#
{
    "683852656036413563": {
        "userID": "406880301449478144",
        "userTag": "Ryle#7974",
        "roleID": "771122102254174279"
    },
    "651231560263008258": {
        "userID": "406880301449478144",
        "userTag": "Ryle#7974",
        "roleID": "841742946776383508"
    },
    "720569527473012738": {
        "roleID": "N/A"
    },
    "655316710751993868": {
        "userID": "406880301449478144",
        "userTag": "Ryle#0008",
        "roleID": "960669367127912518"
    }
}```
#

"server id": {
userID: userid
usertag: usertag
roleID: id of the role
}

dry olive
#

Not sure why you need that, DJS knows all about users and members

#

guild.members.fetch('655316710751993868')

frail vine
#

i just do it for when i look at it. makes it easier to see who changed the role

dry olive
#

ah so it's an audit log?

frail vine
#

kind of. but when the bot runs: newPresence.member.roles.add(listeningRole), listeningRole is pulled from that json file

#

from roleID

dry olive
#

Either way, DB better.
It's the "right way" to do things, not the hacky JSON way πŸ™‚

frail vine
#

yea ik json is bad. just the way i got familiar with

dry olive
#

Don't want to go to an interview, discuss your bot, and them ask "why did you choose JSON for a storage medium"

frail vine
#

plus not knowing DBs is bad enough... but on top of that id have to use DBs on heroku

vagrant ermine
#

couldn't you just clone the object and then save it as a blob?

dry olive
#

Heroku IIRC doesn't have DB, it's just a hosting service.
I have MongoDB through Atlas for a Free DB, the Bot connects to the DB that way

frail vine
#

how does it connect to it? do you upload the DB to heroku too?

dry olive
#

I have this:

databaseConnected = await new Promise((resolve) => {

  try {
    // noinspection JSVoidFunctionReturnValueUsed
    mongoose.connect(MONGODB_SRV, {
      useUnifiedTopology: true,
      useNewUrlParser: true
      // useFindAndModify: false, // option usefindandmodify is not supported
    })
    .then(() => {
      resolve(true);
    })
    .catch(error => {
      console.error('Database connection failed', error);
      resolve(false);
    });
  } catch (error) {
    console.error('Database connection failed', error);
    resolve(false);
  }
});
#

So mongoose.connect directly logs-in to the DB, from Heroku NodeJS instance

frail vine
#

just confused on where its logging into

#

is this database located on your PC?

dry olive
#

MongoDB is a separate host, through Atlas

#

I literally set it up, and haven't logged into it since.

#

I use Mongo Compass to view the data

frail vine
#

hmm. gotta learn about that

dry olive
#

oh that's a tip.

#

Make 2 Bots, and 2 Databases.

#

When you have it Live, it uses one bot and SRV for DB

#

When you run it on your machine, use the other pair.

#

And put each bot in it's own server; so they're all isolated.

#

Nothing worse than trying to do something and deleting Live data 😱

vagrant ermine
#

Question: Why not use sth. like REDIS?

frail vine
vagrant ermine
dry olive
#

Exactly.

#

My Live Bot is always running

#

When I'm working on the bot, it's a different bot, with own server, and own git-branches

#

When I merge to main it deploys the changes to the live-bot

frail vine
#

so you just upload the test bot files to github under the main bots repo
then host it?

dry olive
#

I G2G, my work life needs attention πŸ˜„ but if either of you have questions, you're both welcome to DB me

frail vine
#

Ok. I probably should go to bed honestly

dry olive
#

haha

#

Repo Management is cloud storage for your code basically

frail vine
#

It's 1:30. I gotta do stuff in the morning but got really invested in this convo

#

we talked for like, almost 2 hours lol

vagrant ermine
#

thank you for your time

frail vine
#

^^!

#

anyways. cya guys

dry olive
#

cya

#

@frail vine An overview of Git States

frail vine
#

Ngl so confusing lol. Getting too late for me to dive into another topic tho. And your work life needs attention peepogiggle

#

Anyways I’ll definitely be learning more as I go, I’m taking a coding and game design class next year through the school I attend so hopefully they’re any good. If not I just have 2 really easy classes.

#

I’ll probably try working on getting the bot up later tomorrow. Encouraging to know I can get back into bot developing for free